diff --git a/.github/workflows/max-os.yml b/.github/workflows/max-os.yml
index 3b1c199c..2743ebb8 100644
--- a/.github/workflows/max-os.yml
+++ b/.github/workflows/max-os.yml
@@ -42,7 +42,7 @@ jobs:
- name: Build MaxOS (Release)
run: |
- cd toolchain/post_process
+ cd toolchain/pre_process
./version.sh --force
cd ../../
mkdir -p cmake-build
@@ -58,7 +58,7 @@ jobs:
generate-docs:
# The type of runner that the job will run on
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
# Don't generate docs on dev branch
if: github.ref == 'refs/heads/main'
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
index 41aee021..7f9d6a5d 100644
--- a/.idea/codeStyles/codeStyleConfig.xml
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -1,5 +1,5 @@
-
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6cd1bb4f..b91d86d8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,13 +2,13 @@
CMAKE_MINIMUM_REQUIRED(VERSION 3.0.0)
# Set the project name and the languages
-project(MaxOS C CXX ASM)
+PROJECT(MaxOS C CXX ASM)
# Logs the compiler commands
-set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+SET(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# don't enable runtime type information
-set(CMAKE_SKIP_RPATH TRUE)
+SET(CMAKE_SKIP_RPATH TRUE)
# Set the standard to C++20
SET(CMAKE_CXX_STANDARD 20)
@@ -22,19 +22,37 @@ LINK_DIRECTORIES(${TOOLCHAIN_ROOT_DIR}/${TOOLCHAIN_PLATFORM}/lib/)
# DEBUG / PROD
IF(NOT CMAKE_BUILD_TYPE)
- set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
+ SET(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE)
ENDIF()
-## Set flags based on build type
+# Set flags based on build type
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
- add_definitions(-DTARGET_DEBUG)
+ ADD_DEFINITIONS(-DTARGET_DEBUG)
ENDIF()
+# Function to make a library easier
+function(MAKE_LIBRARY LIBNAME)
+
+ # TODO: ADD_DEPENDENCIES(${LIBNAME} libc) (& for static)
+
+ # Install dynamic library
+ ADD_LIBRARY(${LIBNAME} SHARED ${LIBRARY_SRCS})
+ TARGET_INCLUDE_DIRECTORIES(${LIBNAME} PUBLIC include)
+ INSTALL(TARGETS ${LIBNAME} LIBRARY DESTINATION ${CMAKE_SOURCE_DIR}/filesystem/os/lib)
+
+ # Install static library
+ ADD_LIBRARY(${LIBNAME}_static STATIC ${LIBRARY_SRCS})
+ TARGET_INCLUDE_DIRECTORIES(${LIBNAME}_static PUBLIC include)
+ INSTALL(TARGETS ${LIBNAME}_static DESTINATION ${CMAKE_SOURCE_DIR}/filesystem/os/lib)
+
+ # TODO: Install headers onto fs
+
+endfunction()
+
# Look to build in these directories
ADD_SUBDIRECTORY(kernel)
-#ADD_SUBDIRECTORY(libraries)
+ADD_SUBDIRECTORY(libraries)
ADD_SUBDIRECTORY(programs)
-#ADD_SUBDIRECTORY(ports)
ADD_CUSTOM_TARGET(image
# Everything needs to be installed (compiled) before we can create the disk image
diff --git a/README.md b/README.md
index 236716ba..f98bdcb2 100644
--- a/README.md
+++ b/README.md
@@ -103,6 +103,7 @@ This is the list of required packages to build the operating system from source.
* libisl-dev
* cmake
* telnet
+* rsync
Linux:
```sh
@@ -194,7 +195,7 @@ No user usage so far (userland will be added in the future)
## Roadmap
-
+#### Core Kernel
- [x] Bootloader
- [x] GDT
- [x] IDT
@@ -210,27 +211,30 @@ No user usage so far (userland will be added in the future)
- [x] Paging
- [x] Userspace
- [x] IPC
-- [ ] VFS
+- [x] VFS
- [x] Loading ELF
- [ ] Multiple Cores Support (SMP & Scheduler)
-- [ ] Userland GUI
-- [ ] CLI
+- [ ] Move drivers to userspace
+- [ ] Move VFS to userspace
- [ ] Porting & Dynamically Linking Libc
+- [ ] Move networking to userspace (& rewrite, fix)
+
+#### Userland
+- [ ] GUI
+- [ ] Terminal
+- [ ] Connect to Clion with SMB for files and GDB for debugging in userspace
+- [ ] DOOM Port
- [ ] Self-hosted os
+- [ ] GUI Framework
- [ ] App Framework & System Apps
-- [ ] DOOM Port
-- [ ] UserSpace Drivers
-- [ ] Userspace Networking
-- [ ] Connect to Clion with SMB for files and GDB for debugging in userspace
- [ ] Auto Updater & Image Builder (ISO Release)
- [ ] Store
+- [ ] Security of some sort
- [ ] User Switching
- [ ] Real Hardware Support
-- [ ] Pretty GUI
- [ ] Port NeoVim, Wakatime & Some hot reloader
- [ ] Create port of my 2048
- [ ] Own LibC
-- [ ] Compatibility Layer(s)
See the [open issues](https://github.com/maxtyson123/MaxOS/issues) for a full list of proposed features (and known issues).
diff --git a/docs/Notes.md b/docs/Notes.md
index 9d29d110..ff994afc 100644
--- a/docs/Notes.md
+++ b/docs/Notes.md
@@ -42,6 +42,10 @@ These are my notes relative to various parts of the OS
+NOTE TO SELF: FUNC AS VARIABLE: auto func_name = [&](uint32_t p) {
+ // Code
+};
+
# Hardware Communication
Here are some notes on how the communication with hardware works, this is used for the keyboard and mouse communication and setting up other devices, e.g. GPU
diff --git a/docs/Styles/.clang-format b/docs/Styles/.clang-format
new file mode 100644
index 00000000..2d90114e
--- /dev/null
+++ b/docs/Styles/.clang-format
@@ -0,0 +1,8 @@
+BasedOnStyle: LLVM
+IndentWidth: 2
+ContinuationIndentWidth: 2
+BreakConstructorInitializers: AfterColon
+ConstructorInitializerIndentWidth: 2
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+AllowShortFunctionsOnASingleLine: None
+ColumnLimit: 0
\ No newline at end of file
diff --git a/docs/Syscalls.md b/docs/Syscalls.md
index 1946fb2e..e07ad26c 100644
--- a/docs/Syscalls.md
+++ b/docs/Syscalls.md
@@ -14,17 +14,17 @@ This is helpful for updating syscall table (I don't know if that will even happe
| rax | rdi | rsi | rdx | r10 | r8 | r9 |
## Syscall Table (v1)
-| Number | Name | Description | Arg0 | Arg1 | Arg2 | Arg3 | Arg4 | Arg5 | Return |
-|--------|-----------------------|---------------------------------|----------------------------------------|------------|-------------|------|------|------|------------------------------------------------|
-| 0 | close_process | Exit a process | uint64_t pid (= 0 for current process) | int status | | | | | |
-| 1 | klog | Log a message to the kernel log | char* msg | | | | | | |
-| 2 | created_shared_memory | Create a shared memory region | size_t size | char* name | | | | | void* address (null if failed) |
-| 3 | open_shared_memory | Open a shared memory region | char* name | | | | | | void* address (null if failed) |
-| 4 | allocate_memory | Allocate memory | size_t size | | | | | | void* address (null if failed) |
-| 5 | free_memory | Free memory | void* address | | | | | | |
-| 6 | create_ipc_endpoint | Create an IPC endpoint | char* name | | | | | | void* message buffer address (null if failed) |
-| 7 | send_ipc_message | Send an IPC message | char* name | void* data | size_t size | | | | |
-| 8 | remove_ipc_endpoint | Remove an IPC endpoint | char* name | | | | | | |
-| 9 | thread_yield | Yield the current thread | | | | | | | |
-| 10 | thread_sleep | Put the current thread to sleep | uint64_t time (ms) | | | | | | |
-| 11 | thread_exit | Exit the current thread | | | | | | | |
\ No newline at end of file
+| Number | Name | Description | Arg0 | Arg1 | Arg2 | Arg3 | Arg4 | Arg5 | Return |
+|--------|-----------------|---------------------------------|----------------------------------------|--------------|--------------|--------------|------|------|---------------------------------------|
+| 0 | close_process | Exit a process | uint64_t pid (= 0 for current process) | int status | | | | | |
+| 1 | klog | Log a message to the kernel log | char* msg | | | | | | |
+| 2 | allocate_memory | Allocate memory | size_t size | | | | | | void* address (null if failed) |
+| 3 | free_memory | Free memory | void* address | | | | | | |
+| 4 | resource_create | Create a resource | ResourceType type | char* name | size_t flags | | | | int success (1 = success, 0 = failed) |
+| 5 | resource_open | Open a resource | ResourceType type | char* name | size_t flags | | | | uint64_t handle (0 if failed) |
+| 6 | resource_close | Close a resource | uint64_t handle | size_t flags | | | | | |
+| 7 | resource_write | Write to a resource | uint64_t handle | void* buffer | size_t size | size_t flags | | | size_t bytes written (0 if failed) |
+| 8 | resource_read | Read from a resource | uint64_t handle | void* buffer | size_t size | size_t flags | | | size_t bytes read (0 if failed) |
+| 9 | thread_yield | Yield the current thread | | | | | | | |
+| 10 | thread_sleep | Put the current thread to sleep | uint64_t time (ms) | | | | | | |
+| 11 | thread_exit | Exit the current thread | | | | | | | |
\ No newline at end of file
diff --git a/filesystem/boot/grub/grub.cfg b/filesystem/boot/grub/grub.cfg
old mode 100644
new mode 100755
index dfe59552..1977c537
--- a/filesystem/boot/grub/grub.cfg
+++ b/filesystem/boot/grub/grub.cfg
@@ -7,7 +7,7 @@ menuentry "Max OS" {
echo "Loading Kernel..."
multiboot2 /boot/MaxOSk64
echo "Loading Test Elf..."
- module2 /boot/test.elf Receiver
- module2 /boot/test1.elf Sender
+ module2 /boot/test.elf File
+ module2 /boot/test1.elf Folder
boot
}
\ No newline at end of file
diff --git a/filesystem/os/.gitkeep b/filesystem/os/lib/.gitkeep
old mode 100644
new mode 100755
similarity index 100%
rename from filesystem/os/.gitkeep
rename to filesystem/os/lib/.gitkeep
diff --git a/filesystem/test/longfilename.extension b/filesystem/test/longfilename.extension
new file mode 100755
index 00000000..0371c1f1
--- /dev/null
+++ b/filesystem/test/longfilename.extension
@@ -0,0 +1 @@
+test data to read
\ No newline at end of file
diff --git a/filesystem/user/.gitkeep b/filesystem/user/.gitkeep
old mode 100644
new mode 100755
diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt
index cb05c1f0..7696a80d 100644
--- a/kernel/CMakeLists.txt
+++ b/kernel/CMakeLists.txt
@@ -13,25 +13,30 @@ SET_SOURCE_FILES_PROPERTIES(${ASM_SRCS} PROPERTIES LANGUAGE ASM)
# Find all the cpp and s files in the src directory (recursive)
FILE(GLOB_RECURSE KERNEL_SRCS src/*.cpp src/*.s)
-# Create the kernel
-ADD_EXECUTABLE(MaxOSk64 ${KERNEL_SRCS})
-TARGET_COMPILE_DEFINITIONS(MaxOSk64 PUBLIC MAXOS_KERNEL)
-
# Update the version before building
+SET(VERSION_HEADER "${CMAKE_SOURCE_DIR}/kernel/include/common/version.h")
+SET(VERSION_HEADER_TMP "${CMAKE_SOURCE_DIR}/kernel/include/common/version.h.tmp")
+SET(POST_PROCESS_SCRIPT "${CMAKE_SOURCE_DIR}/toolchain/pre_process/run.sh")
ADD_CUSTOM_COMMAND(
- COMMENT "post_processing kernel"
- TARGET MaxOSk64
- PRE_BUILD
- COMMAND ${CMAKE_SOURCE_DIR}/toolchain/post_process/run.sh
- COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_SOURCE_DIR}/kernel/include/common/version.h.tmp ${CMAKE_SOURCE_DIR}/kernel/include/common/version.h
- COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_SOURCE_DIR}/kernel/include/common/version.h.tmp
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT "${VERSION_HEADER}"
+ COMMAND "${POST_PROCESS_SCRIPT}"
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different "${VERSION_HEADER_TMP}" "${VERSION_HEADER}"
+ COMMAND ${CMAKE_COMMAND} -E remove "${VERSION_HEADER_TMP}"
+ DEPENDS ${KERNEL_SRCS}
+ WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
+ COMMENT "Regenerating version.h because kernel sources changed"
)
+ADD_CUSTOM_TARGET(VersionScript DEPENDS "${VERSION_HEADER}")
+
+# Create the kernel
+ADD_EXECUTABLE(MaxOSk64 ${KERNEL_SRCS} ${VERSION_HEADER})
+ADD_DEPENDENCIES(MaxOSk64 VersionScript)
+TARGET_COMPILE_DEFINITIONS(MaxOSk64 PUBLIC MAXOS_KERNEL)
# Linker
SET(LINKER_SCRIPT ${CMAKE_SOURCE_DIR}/kernel/src/linker.ld)
SET_TARGET_PROPERTIES(MaxOSk64 PROPERTIES LINK_DEPENDS ${LINKER_SCRIPT})
-TARGET_LINK_LIBRARIES(MaxOSk64 gcc)
+TARGET_LINK_LIBRARIES(MaxOSk64 PRIVATE gcc syscore_static)
TARGET_LINK_OPTIONS(MaxOSk64 PRIVATE -T ${LINKER_SCRIPT} -nostdlib -n)
# Set the include directories
diff --git a/kernel/include/common/buffer.h b/kernel/include/common/buffer.h
new file mode 100644
index 00000000..4e825e08
--- /dev/null
+++ b/kernel/include/common/buffer.h
@@ -0,0 +1,73 @@
+//
+// Created by 98max on 30/07/2025.
+//
+
+#ifndef MAXOS_COMMON_BUFFER_H
+#define MAXOS_COMMON_BUFFER_H
+
+#include
+#include
+#include
+#include
+
+namespace MaxOS{
+
+ namespace common{
+
+ /**
+ * @class Buffer
+ * @brief Wrapper class for a region of bytes in memor in an attempt to add some memory safety. Automatically
+ * allocates the size specified and frees it once done, adds boundary to I/O.
+ */
+ class Buffer{
+
+ private:
+ uint8_t* m_bytes = nullptr;
+ size_t m_capacity;
+ bool m_dont_delete = false;
+
+ size_t m_offset = 0;
+
+ public:
+ Buffer(size_t size, bool update_offset = true);
+ Buffer(void* source, size_t size, bool update_offset = true);
+ ~Buffer();
+
+ [[nodiscard]] uint8_t* raw() const;
+
+ void clear();
+ void full(uint8_t byte, size_t offset = 0, size_t amount = 0);
+
+ bool update_offset = true;
+ void set_offset(size_t offset);
+
+ [[nodiscard]] size_t capacity() const;
+ void resize(size_t size);
+
+ void write(uint8_t byte);
+ void write(size_t offset, uint8_t byte);
+ uint8_t read();
+ uint8_t read(size_t offset);
+
+ void copy_from(const Buffer* buffer);
+ void copy_from(const Buffer* buffer, size_t length);
+ void copy_from(const Buffer* buffer, size_t length, size_t offset);
+ void copy_from(const Buffer* buffer, size_t length, size_t offset, size_t offset_other);
+ void copy_from(const void* source, size_t length);
+ void copy_from(const void* source, size_t length, size_t offset);
+
+ void copy_to(Buffer* buffer);
+ void copy_to(Buffer* buffer, size_t length);
+ void copy_to(Buffer* buffer, size_t length, size_t offset);
+ void copy_to(Buffer* buffer, size_t length, size_t offset, size_t offset_other);
+ void copy_to(void* destination, size_t length);
+ void copy_to(void* destination, size_t length, size_t offset);
+ };
+
+ typedef Buffer buffer_t;
+
+ }
+
+}
+
+#endif //MAXOS_COMMON_BUFFER_H
diff --git a/kernel/include/common/eventHandler.h b/kernel/include/common/eventHandler.h
index 4a82b0f0..57b3cb8b 100644
--- a/kernel/include/common/eventHandler.h
+++ b/kernel/include/common/eventHandler.h
@@ -8,6 +8,11 @@
#include
#include
+
+
+// TODO: - Event doesnt need to be a class should be a struct
+// - With moving to micro kernel this should be moved to a external lib as not needed in the kernel
+
namespace MaxOS{
namespace common{
diff --git a/kernel/include/common/logger.h b/kernel/include/common/logger.h
index d9f822dd..907315b7 100644
--- a/kernel/include/common/logger.h
+++ b/kernel/include/common/logger.h
@@ -7,7 +7,6 @@
#include
#include
-#include
@@ -40,7 +39,7 @@
bool m_log_writers_enabled[m_max_log_writers] = {false, false, false, false, false};
// Progress bar
- static const uint8_t s_progress_total = 25;
+ static inline uint8_t s_progress_total = 100;
uint8_t m_progress_current = 0;
static inline Logger* s_active_logger = nullptr;
@@ -58,7 +57,6 @@
void set_log_level(LogLevel log_level);
void write_char(char c) final;
- void lineFeed() final;
void printf(const char* format, ...);
static void ASSERT(bool condition, const char* message, ...);
@@ -77,5 +75,17 @@
Logger& operator << (LogLevel log_level);
};
+ /**
+ * @brief If the specified condition is not met then the kernel will crash with the specified message.
+ *
+ * This macro wraps Logger::ASSERT and supports printf-style formatting with variadic arguments.
+ *
+ * @param condition The condition to check.
+ * @param format The format string (like printf).
+ * @param ... Additional arguments to format.
+ *
+ * @see Logger::ASSERT
+ */
#define ASSERT(condition, format, ...) Logger::ASSERT(condition, format, ##__VA_ARGS__)
+
#endif // MAXOS_COMMON_LOGGER_H
diff --git a/kernel/include/common/map.h b/kernel/include/common/map.h
index f309e939..efe0aae1 100644
--- a/kernel/include/common/map.h
+++ b/kernel/include/common/map.h
@@ -42,27 +42,39 @@ namespace MaxOS{
Vector> m_elements;
public:
- typedef typename Vector >::iterator iterator;
+ typedef typename Vector>::iterator iterator;
Map();
~Map();
- Value& operator[](Key);
+ Value& operator[](Key);
+
+ bool empty();
+ int size();
+
iterator begin();
iterator end();
iterator find(Key);
- bool empty();
- void clear();
- void insert(Key, Value);
- void erase(Key);
+ iterator push_back(Key, Value);
+ Pair pop_back();
+
+ iterator push_front(Key, Value);
+ Pair pop_front();
+
+ void insert(Key, Value);
+
+ void erase(Key);
+ void erase(iterator position);
+ void clear();
void iterate(MapIterationHandler* handler);
void iterate(void callback(Key&, Value&));
};
- /// ______________ TEMPLATE IMPLEMENTATION ______________
+
+ /// ______________ TEMPLATE IMPLEMENTATION ______________
template MapIterationHandler::MapIterationHandler() = default;
template MapIterationHandler::~MapIterationHandler() = default;
@@ -137,21 +149,33 @@ namespace MaxOS{
*/
template typename Map::iterator Map::find(Key element) {
- // Loop through the elements
- for (iterator it = begin(); it != end(); it++) {
-
- // If the key of the current element is equal to the key we are looking for
- if (it -> first == element) {
- // Return the iterator
+ // Search for the element
+ for (iterator it = begin(); it != end(); it++)
+ if (it -> first == element)
return it;
- }
- }
- // If it is not found, return the end iterator
+ // Item not found
return end();
}
+ template Map::iterator Map::push_back(Key key, Value value) {
+ return m_elements.push_back(Pair(key, value));
+ }
+
+ template Pair Map::pop_back() {
+ return m_elements.pop_back();
+ }
+
+ template Map::iterator Map::push_front(Key key, Value value) {
+ return m_elements.push_front({key, value});
+ }
+
+ template Pair Map::pop_front() {
+ return m_elements.pop_front();
+ }
+
+
/**
* @brief Returns whether the map is empty
*
@@ -163,6 +187,18 @@ namespace MaxOS{
return m_elements.empty();
}
+ /**
+ * @brief The number of elements in the map
+ *
+ * @return The number of elements in the Map
+ */
+ template int Map::size()
+ {
+ // Return the size of the vector
+ return m_elements.size();
+
+ }
+
/**
* @brief Removes all elements from the map
*
@@ -214,6 +250,11 @@ namespace MaxOS{
}
+ template void Map::erase(Map::iterator position) {
+ m_elements.erase(position);
+
+ }
+
/**
* @brief Iterates through the map and calls the handler
*
diff --git a/kernel/include/common/string.h b/kernel/include/common/string.h
index f898ab53..20da7721 100644
--- a/kernel/include/common/string.h
+++ b/kernel/include/common/string.h
@@ -7,6 +7,8 @@
#include
+#include
+
namespace MaxOS {
/**
@@ -16,14 +18,21 @@ namespace MaxOS {
class String {
private:
char* m_string = nullptr;
- int m_length = 0;
+ int m_length = 0; // Does not include the null terminator
+
+ const static uint8_t s_small_storage = 0x99;
+ char m_small_string[s_small_storage];
+ bool m_using_small = true;
[[nodiscard]] static int lex_value(String const &other) ;
+ void allocate_self();
public:
String();
+ explicit String(char c);
String(char const* string);
+ String(uint8_t const* string, int length);
String(String const &other);
String(int value);
String(uint64_t value);
@@ -34,7 +43,14 @@ namespace MaxOS {
[[nodiscard]] int length(bool count_ansi = true) const;
char* c_str();
- [[nodiscard]] const char* c_str() const;
+ const char* c_str() const;
+
+ bool starts_with(String const &other);
+ String substring(int start, int length) const;
+
+ common::Vector split(String const &delimiter) const;
+ String strip(char strip_char = ' ') const;
+
[[nodiscard]] String center(int width, char fill = ' ') const;
diff --git a/kernel/include/common/vector.h b/kernel/include/common/vector.h
index 16a6a042..077ccd18 100644
--- a/kernel/include/common/vector.h
+++ b/kernel/include/common/vector.h
@@ -47,22 +47,26 @@ namespace MaxOS{
Vector();
Vector(int Size, Type element);
+ Vector(const Vector& other);
+ Vector(Vector&& other);
~Vector();
Type& operator[](uint32_t index) const;
+ Vector& operator=(const Vector& other);
+ Vector& operator=(Vector&& other);
[[nodiscard]] bool empty() const;
- [[nodiscard]] uint32_t size() const;
+ [[nodiscard]] uint32_t size() const;
iterator begin() const;
iterator end() const;
iterator find(Type) const;
iterator push_back(Type);
- void pop_back();
+ Type pop_back();
iterator push_front(Type);
- void pop_front();
+ Type pop_front();
void erase(Type);
void erase(iterator position);
@@ -72,7 +76,7 @@ namespace MaxOS{
void Iterate(void callback(Type&));
};
- ///______________________________________Implementation__________________________________________________
+ ///______________________________________Implementation__________________________________________________
/**
* @brief Constructor for Vector
*
@@ -96,12 +100,48 @@ namespace MaxOS{
// Allocate space for the array
m_elements = new Type[size];
+ m_capacity = size > 0 ? size : 1;
+ m_size = 0;
// Push all the elements to the Vector
for (int i = 0; i < size; ++i)
push_back(element);
}
+ /**
+ * @brief Copy constructor for Vector
+ *
+ * @tparam Type The type of data to be stored
+ * @param other The vector to copy from
+ */
+ template Vector::Vector(const Vector& other)
+ : m_size(other.m_size),
+ m_capacity(other.m_capacity)
+ {
+ // Copy each element into a new array
+ m_elements = new Type[m_capacity];
+ for (uint32_t i = 0; i < m_size; ++i)
+ m_elements[i] = other.m_elements[i];
+ }
+
+ /**
+ * @brief Move constructor for Vector
+ *
+ * @tparam Type The type of data to be stored
+ * @param other The vector to copy from
+ */
+ template Vector::Vector(Vector &&other)
+ : m_elements(other.m_elements),
+ m_size(other.m_size),
+ m_capacity(other.m_capacity)
+ {
+
+ // Clear the other Vector
+ other.m_elements = nullptr;
+ other.m_size = 0;
+ other.m_capacity = 0;
+
+ }
template Vector::~Vector() {
@@ -117,6 +157,7 @@ namespace MaxOS{
*/
template void Vector::increase_size() {
+
// Allocate more space for the array
Type* new_elements = new Type[m_capacity * 2];
@@ -145,7 +186,7 @@ namespace MaxOS{
template Type &Vector::operator[](uint32_t index) const{
// If the index is in the Vector
- if (index <= m_size)
+ if (index < m_size)
return m_elements[index];
// Return the last element of the Vector
@@ -153,6 +194,59 @@ namespace MaxOS{
}
+ /**
+ * @brief Assignment by copy, data is copied into a new buffer stored in this vector
+ *
+ * @tparam Type Type of the Vector
+ * @param other The vector to copy from
+ * @return This vector, with the copied elements
+ */
+ template Vector& Vector::operator=(const Vector& other) {
+
+ // Setting to itself?
+ if (this == &other)
+ return *this;
+
+ // Create a new buffer to store the elements
+ delete[] m_elements;
+ m_elements = new Type[other.m_capacity];
+
+ // Copy data
+ m_size = other.m_size;
+ m_capacity = other.m_capacity;
+ for (uint32_t i = 0; i < m_size; ++i)
+ m_elements[i] = other.m_elements[i];
+
+ return *this;
+ }
+
+ /**
+ * @brief Assignment by move, data is moved into the buffer stored in this vector and the other vector is cleared
+ *
+ * @tparam Type Type of the Vector
+ * @param other The vector to copy from
+ * @return This vector, with the copied elements
+ */
+ template Vector& Vector::operator=(Vector&& other) noexcept {
+
+ // Moving to itself?
+ if (this == &other)
+ return *this;
+
+ // Move into this vector
+ delete[] m_elements;
+ m_elements = other.m_elements;
+ m_size = other.m_size;
+ m_capacity = other.m_capacity;
+
+ // Remove from other vector
+ other.m_elements = nullptr;
+ other.m_size = 0;
+ other.m_capacity = 0;
+
+ return *this;
+ }
+
/**
* @brief Returns the number of elements in the Vector
*
@@ -164,10 +258,10 @@ namespace MaxOS{
}
/**
- * @brief Returns the m_first_memory_chunk element of the Vector
+ * @brief Returns the first element of the Vector
*
* @tparam Type Type of the Vector
- * @return The m_first_memory_chunk element of the Vector
+ * @return The first element of the Vector
*/
template typename Vector::iterator Vector::begin() const{
return &m_elements[0];
@@ -234,11 +328,13 @@ namespace MaxOS{
* @brief Removes the last element from the Vector
* @tparam Type Type of the Vector
*/
- template void Vector::pop_back() {
+ template Type Vector::pop_back() {
// Remove the last element from the Vector
if (m_size > 0)
--m_size;
+
+ return m_elements[m_size];
}
/**
@@ -251,9 +347,8 @@ namespace MaxOS{
template typename Vector::iterator Vector::push_front(Type element) {
// Check if we need to allocate more space for the array
- if(m_size == m_capacity){
+ if(m_size == m_capacity)
increase_size();
- }
// Move all elements one index to the right
for (iterator i = end(); i > begin(); --i)
@@ -271,19 +366,25 @@ namespace MaxOS{
* @brief Removes the m_first_memory_chunk element from the Vector
*
* @tparam Type Type of the Vector
+ * @return The element that was removed, or a default constructed element if the Vector is empty
*/
- template void Vector::pop_front() {
+ template Type Vector::pop_front() {
- // Make sure the Vector is not empty
- if (m_size == 0)
- return;
+ // Make sure the Vector is not empty
+ if (m_size == 0)
+ return Type();
- // Move all elements one index to the left
- for (iterator i = begin(); i != end(); ++i)
- *i = *(i + 1);
+ // Store the element to return
- // Decrease the size of the Vector
- --m_size;
+ Type element = m_elements[0];
+
+ // Move all elements one index to the left
+ for (uint32_t i = 0; i < m_size - 1; ++i)
+ m_elements[i] = m_elements[i + 1];
+
+ // Decrease the size of the Vector
+ --m_size;
+ return element;
}
/**
diff --git a/kernel/include/drivers/clock/clock.h b/kernel/include/drivers/clock/clock.h
index 6a0e8653..7785f01c 100644
--- a/kernel/include/drivers/clock/clock.h
+++ b/kernel/include/drivers/clock/clock.h
@@ -151,11 +151,13 @@ namespace MaxOS {
uint8_t read_hardware_clock(uint8_t address);
[[nodiscard]] uint8_t binary_representation(uint8_t number) const;
+ inline static Clock* s_active_clock = nullptr;
+
public:
Clock(hardwarecommunication::AdvancedProgrammableInterruptController* apic, uint16_t time_between_events = 10);
~Clock();
- inline static uint64_t s_clock_accuracy = 1;
+ uint64_t clock_accuracy = 1;
void activate() override;
void delay(uint32_t milliseconds) const;
@@ -165,6 +167,8 @@ namespace MaxOS {
string vendor_name() final;
string device_name() final;
+
+ static Clock* active_clock();
};
}
diff --git a/kernel/include/drivers/disk/ata.h b/kernel/include/drivers/disk/ata.h
index 521bdc5a..4eff54e4 100644
--- a/kernel/include/drivers/disk/ata.h
+++ b/kernel/include/drivers/disk/ata.h
@@ -2,12 +2,13 @@
// Created by 98max on 24/10/2022.
//
-#ifndef MAXOS_DRIVERS_ATA_H
-#define MAXOS_DRIVERS_ATA_H
+#ifndef MAXOS_DRIVERS_DISK_ATA_H
+#define MAXOS_DRIVERS_DISK_ATA_H
+#include
#include
#include
-#include
+#include
#include
@@ -21,7 +22,7 @@ namespace MaxOS{
* @class AdvancedTechnologyAttachment
* @brief Driver for the ATA controller, handles the reading and writing of data to the hard drive
*/
- class AdvancedTechnologyAttachment : public Driver {
+ class AdvancedTechnologyAttachment : public Disk {
protected:
hardwarecommunication::Port16Bit m_data_port;
@@ -36,17 +37,14 @@ namespace MaxOS{
bool m_is_master;
uint16_t m_bytes_per_sector { 512 };
- common::OutputStream* ata_message_stream;
public:
- AdvancedTechnologyAttachment(uint16_t port_base, bool master, common::OutputStream* output_stream);
+ AdvancedTechnologyAttachment(uint16_t port_base, bool master);
~AdvancedTechnologyAttachment();
- void identify();
- void read_28(uint32_t sector, uint8_t* data, int count);
- void write_28(uint32_t sector, const uint8_t* data, int count);
- void flush();
-
- void activate() final;
+ bool identify();
+ void read(uint32_t sector, common::buffer_t* data_buffer, size_t amount) final;
+ void write(uint32_t sector, const common::buffer_t* data, size_t count) final;
+ void flush() final;
string device_name() final;
string vendor_name() final;
@@ -55,4 +53,4 @@ namespace MaxOS{
}
}
-#endif //MAXOS_DRIVERS_ATA_H
+#endif //MAXOS_DRIVERS_DISK_ATA_H
diff --git a/kernel/include/drivers/disk/disk.h b/kernel/include/drivers/disk/disk.h
new file mode 100644
index 00000000..f51626e6
--- /dev/null
+++ b/kernel/include/drivers/disk/disk.h
@@ -0,0 +1,47 @@
+//
+// Created by 98max on 18/04/2025.
+//
+
+#ifndef MAXOS_DRIVERS_DISK_H
+#define MAXOS_DRIVERS_DISK_H
+
+#include
+#include
+#include
+#include
+
+
+namespace MaxOS{
+
+ namespace drivers{
+
+ namespace disk{
+
+ /**
+ * @class Disk
+ * @brief Generic Disk, handles the reading and writing of data to the hard drive
+ */
+ class Disk : public Driver {
+
+ public:
+ Disk();
+ ~Disk();
+
+ void read(uint32_t sector, common::buffer_t* data_buffer);
+ virtual void read(uint32_t sector, common::buffer_t* data_buffer, size_t amount);
+
+ void write(uint32_t sector, const common::buffer_t* data);
+ virtual void write(uint32_t sector, const common::buffer_t* data, size_t count);
+
+ virtual void flush();
+
+ void activate() override;
+
+ string device_name() override;
+ string vendor_name() override;
+ };
+ }
+ }
+}
+
+#endif //MAXOS_DRIVERS_DISK_H
diff --git a/kernel/include/drivers/disk/ide.h b/kernel/include/drivers/disk/ide.h
new file mode 100644
index 00000000..2bcbd693
--- /dev/null
+++ b/kernel/include/drivers/disk/ide.h
@@ -0,0 +1,47 @@
+//
+// Created by Max Tyson on 18/04/2025.
+//
+
+#ifndef MAXOS_DRIVERS_IDE_H
+#define MAXOS_DRIVERS_IDE_H
+
+#include
+#include
+#include
+#include
+#include
+
+
+namespace MaxOS{
+
+ namespace drivers{
+
+ namespace disk{
+
+ /**
+ * * @class IntegratedDriveElectronicsController
+ * @brief Driver for the IDE controller, handles the creation and management of the IDE devices
+ */
+ class IntegratedDriveElectronicsController : public Driver{
+
+
+ common::Map devices;
+
+ public:
+ IntegratedDriveElectronicsController(hardwarecommunication::PeripheralComponentInterconnectDeviceDescriptor* device_descriptor);
+ ~IntegratedDriveElectronicsController();
+
+ void initialise() final;
+ void activate() final;
+
+ string vendor_name() final;
+ string device_name() final;
+
+
+ };
+ }
+ }
+}
+
+
+#endif //MAXOS_DRIVERS_IDE_H
diff --git a/kernel/include/drivers/driver.h b/kernel/include/drivers/driver.h
index bd77ce12..9fb64b02 100644
--- a/kernel/include/drivers/driver.h
+++ b/kernel/include/drivers/driver.h
@@ -22,19 +22,11 @@ namespace MaxOS
* @brief base class for all drivers, handles the activation, deactivation, initialisation and reset of the driver as well as error messages and identifying the device
*/
class Driver {
- protected:
public:
- common::OutputStream* m_driver_message_stream;
-
- Driver(common::OutputStream* driverMessageStream = nullptr);
+ Driver();
~Driver();
- void error_message(const string& message) const;
- void error_message(char char_to_write) const;
- void error_message(int int_to_write) const;
- void error_message(uint32_t hex_to_write) const;
-
virtual void activate();
virtual void deactivate();
virtual void initialise();
diff --git a/kernel/include/drivers/ethernet/amd_am79c973.h b/kernel/include/drivers/ethernet/amd_am79c973.h
index 442b1e40..8bdb41a3 100644
--- a/kernel/include/drivers/ethernet/amd_am79c973.h
+++ b/kernel/include/drivers/ethernet/amd_am79c973.h
@@ -8,7 +8,6 @@
#include
#include
#include
-#include
#include
#include
@@ -86,7 +85,7 @@ namespace MaxOS{
void FetchDataSent(); //Fetches the data from the buffer
public:
- AMD_AM79C973(hardwarecommunication::PeripheralComponentInterconnectDeviceDescriptor* deviceDescriptor, common::OutputStream* amdNetMessageStream = nullptr);
+ AMD_AM79C973(hardwarecommunication::PeripheralComponentInterconnectDeviceDescriptor* device_descriptor);
~AMD_AM79C973();
//Override driver default methods
diff --git a/kernel/include/drivers/ethernet/ethernet.h b/kernel/include/drivers/ethernet/ethernet.h
index 36b9363d..e300eda0 100644
--- a/kernel/include/drivers/ethernet/ethernet.h
+++ b/kernel/include/drivers/ethernet/ethernet.h
@@ -90,7 +90,7 @@ namespace MaxOS{
void FireDataSent(uint8_t* buffer, uint32_t size);
public:
- EthernetDriver(common::OutputStream* ethernetMessageStream);
+ EthernetDriver();
~EthernetDriver();
static MediaAccessControlAddress CreateMediaAccessControlAddress(uint8_t digit1, uint8_t digit2, uint8_t digit3, uint8_t digit4, uint8_t digit5, uint8_t digit6);
diff --git a/kernel/include/drivers/peripherals/keyboard.h b/kernel/include/drivers/peripherals/keyboard.h
index 0e6f95e9..db0712b9 100644
--- a/kernel/include/drivers/peripherals/keyboard.h
+++ b/kernel/include/drivers/peripherals/keyboard.h
@@ -22,6 +22,12 @@ namespace MaxOS
namespace peripherals{
+ enum class ScanCodeType : int{
+ REGULAR,
+ EXTENDED,
+ EXTENDED_BUFFER
+ };
+
enum class KeyCode : uint16_t{
// Alphabet
diff --git a/kernel/include/drivers/peripherals/mouse.h b/kernel/include/drivers/peripherals/mouse.h
index f07daa4b..b0abd178 100644
--- a/kernel/include/drivers/peripherals/mouse.h
+++ b/kernel/include/drivers/peripherals/mouse.h
@@ -86,9 +86,9 @@ namespace MaxOS {
void handle_interrupt() final;
- uint8_t buffer[3] = {};
- uint8_t offset = 0;
- uint8_t buttons = 0;
+ uint8_t m_buffer[3] = {};
+ uint8_t m_offset = 0;
+ uint8_t m_buttons = 0;
public:
MouseDriver();
diff --git a/kernel/include/drivers/video/vesa.h b/kernel/include/drivers/video/vesa.h
index 7b5ac4b4..3fb56234 100644
--- a/kernel/include/drivers/video/vesa.h
+++ b/kernel/include/drivers/video/vesa.h
@@ -25,9 +25,6 @@ namespace MaxOS {
*/
class VideoElectronicsStandardsAssociation : public VideoDriver {
- private:
- static bool init();
-
protected:
bool internal_set_mode(uint32_t width, uint32_t height, uint32_t) final;
diff --git a/kernel/include/filesystem/fat32.h b/kernel/include/filesystem/fat32.h
deleted file mode 100644
index 41fc8d01..00000000
--- a/kernel/include/filesystem/fat32.h
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// Created by 98max on 1/01/2023.
-//
-
-#ifndef MAXOS_FILESYSTEM_FAT32_H
-#define MAXOS_FILESYSTEM_FAT32_H
-
-#include "drivers/disk/ata.h"
-#include
-#include
-#include
-#include
-#include
-
-namespace MaxOS{
-
- namespace filesystem{
-
- /**
- * @struct BiosParameterBlock
- * @brief Stores information about the FAT32 filesystem
- */
- struct BiosParameterBlock32{
-
- uint8_t jump[3];
- uint8_t OEM_name[8];
- uint16_t bytes_per_sector;
- uint8_t sectors_per_cluster;
- uint16_t reserved_sectors;
- uint8_t table_copies;
- uint16_t root_entries;
- uint16_t total_sectors_16;
- uint8_t media_type;
- uint16_t fat_sector_count;
- uint16_t sectors_per_track;
- uint16_t head_count;
- uint32_t hidden_sectors;
- uint32_t total_sectors_32;
-
- uint32_t table_size_32;
- uint16_t extended_flags;
- uint16_t fat_version;
- uint32_t root_cluster;
- uint16_t fat_info;
- uint16_t backup_sector;
- uint8_t reserved0[12];
- uint8_t drive_number;
- uint8_t reserved_1;
- uint8_t boot_signature;
- uint32_t uint_32;
- uint8_t volume_label[11];
- uint8_t file_system_type[8];
-
- } __attribute__((packed));
-
- /**
- * @struct DirectoryEntry
- * @brief Stores information about a file or directory
- */
- struct DirectoryEntry{
-
- uint8_t name[8];
- uint8_t extension[3];
- uint8_t attributes;
- uint8_t reserved;
-
- uint8_t creation_time_tenth;
- uint16_t creation_time;
- uint16_t creation_date;
- uint16_t last_access_date;
-
- uint16_t first_cluster_high;
-
- uint16_t last_write_time;
- uint16_t last_write_date;
-
- uint16_t first_cluster_low;
-
- uint32_t size;
-
- } __attribute__((packed));
-
-
- // TODO: Redo FAT32
- }
-}
-
-#endif //MAXOS_FILESYSTEM_FAT32_H
diff --git a/kernel/include/filesystem/filesystem.h b/kernel/include/filesystem/filesystem.h
index f6009cdb..67008069 100644
--- a/kernel/include/filesystem/filesystem.h
+++ b/kernel/include/filesystem/filesystem.h
@@ -6,21 +6,107 @@
#define MAXOS_FILESYSTEM_FILESYSTEM_H
#include
+#include
#include
+#include
+#include
+#include
+#include
namespace MaxOS{
namespace filesystem{
+ // Easier to read
+ typedef uint32_t lba_t;
+ typedef syscore::filesystem::SeekType SeekType;
- enum class SeekType{
- SET,
- CUR,
- END
+ /**
+ * @class File
+ * @brief Handles file operations and information
+ */
+ class File
+ {
+
+ protected:
+ uint32_t m_offset;
+ string m_name;
+ size_t m_size;
+
+ public:
+ File();
+ virtual ~File();
+
+ virtual void write(const common::buffer_t* data, size_t size);
+ virtual void read(common::buffer_t* data, size_t size);
+ virtual void flush();
+
+ void seek(SeekType seek_type, size_t offset);
+ uint32_t position();
+
+ size_t size();
+ string name();
};
- // TODO: Redo this class
+ /**
+ * @class Directory
+ * @brief Handles a group of files (directory)
+ */
+ class Directory
+ {
+ protected:
+ common::Vector m_files;
+ common::Vector m_subdirectories;
+
+ string m_name;
+
+ public:
+ Directory();
+ virtual ~Directory();
+
+ virtual void read_from_disk();
+
+ common::Vector files();
+ common::Vector subdirectories();
+
+ File* open_file(const string& name);
+ Directory* open_subdirectory(const string& name);
+
+ virtual File* create_file(const string& name);
+ virtual void remove_file(const string& name);
+
+ void rename_file(File* file, const string& new_name);
+ virtual void rename_file(const string& old_name, const string& new_name);
+
+ void rename_subdirectory(Directory* directory, const string& new_name);
+ virtual void rename_subdirectory(const string& old_name, const string& new_name);
+
+ virtual Directory* create_subdirectory(const string& name);
+ virtual void remove_subdirectory(const string& name);
+
+ string name();
+ size_t size();
+ };
+
+ /**
+ * @class FileSystem
+ * @brief Handles the disk operations and file system information
+ */
+ class FileSystem
+ {
+ protected:
+ Directory* m_root_directory;
+
+ public:
+ FileSystem();
+ virtual ~FileSystem();
+
+ Directory* root_directory();
+ Directory* get_directory(const string& path);
+
+ bool exists(const string& path);
+ };
}
diff --git a/kernel/include/filesystem/format/ext2.h b/kernel/include/filesystem/format/ext2.h
new file mode 100644
index 00000000..79df5e54
--- /dev/null
+++ b/kernel/include/filesystem/format/ext2.h
@@ -0,0 +1,382 @@
+//
+// Created by 98max on 17/07/2025.
+//
+
+#ifndef MAXOS_FILESYSTEM_EXT2_H
+#define MAXOS_FILESYSTEM_EXT2_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace MaxOS {
+ namespace filesystem {
+ namespace format{
+ namespace ext2{
+
+
+ typedef struct SuperBlock{
+ uint32_t total_inodes;
+ uint32_t total_blocks;
+ uint32_t reserved_blocks;
+ uint32_t unallocated_blocks;
+ uint32_t unallocated_inodes;
+ uint32_t starting_block;
+ uint32_t block_size;
+ uint32_t fragment_size;
+ uint32_t blocks_per_group;
+ uint32_t fragments_per_group;
+ uint32_t inodes_per_group;
+ uint32_t last_mount_time;
+ uint32_t late_write_time;
+ uint16_t mounts_since_check;
+ uint16_t mounts_until_check;
+ uint16_t signature;
+ uint16_t state;
+ uint16_t error_operation;
+ uint16_t version_minor;
+ uint32_t last_check_time;
+ uint32_t time_until_check;
+ uint32_t os_id;
+ uint32_t version_major;
+ uint16_t reserved_user;
+ uint16_t reserved_group;
+
+ // Extended Fields (version >= 1)
+ uint32_t first_inode;
+ uint16_t inode_size;
+ uint16_t superblock_group;
+ uint32_t optional_features;
+ uint32_t required_features;
+ uint16_t read_only_features;
+ uint8_t filesystem_id[16];
+ uint8_t volume_name[16];
+ uint8_t last_mount_path[64];
+ uint32_t compression;
+ uint8_t file_preallocation_blocks;
+ uint8_t directory_preallocation_blocks;
+ uint16_t unused;
+ uint8_t journal_id[16];
+ uint32_t journal_inode;
+ uint32_t journal_device;
+ uint32_t orphan_inodes_start;
+ uint8_t free[276];
+
+ } __attribute__((packed)) superblock_t;
+
+
+ enum class FileSystemState{
+ CLEAN = 1,
+ ERROR = 2,
+ };
+
+ enum class ErrorOperation{
+ IGNORE = 1,
+ REMOUNT = 2,
+ PANIC = 3,
+ };
+
+ enum class CreatorOS{
+ LINUX,
+ GNU_HURD,
+ MASIX,
+ FREE_BSD,
+ OTHER_LITES,
+ };
+
+ enum class OptionalFeatures{
+ PREALLOCATE_DIRECTORY = 0x1,
+ AFS_SERVER_INODES = 0x2,
+ JOURNAL_ENABLED = 0x4,
+ ATTRIBUTES_EXTENDED = 0x8,
+ RESIZEABLE = 0x10,
+ HASH_INDEXING = 0x20,
+ };
+
+ enum class RequiredFeatures {
+ COMPRESSION = 0x1,
+ DIRECTORY_HAS_TYPE = 0x2,
+ MUST_REPLAY_JOURNAL = 0x4,
+ JOURNAL_DEVICE = 0x8,
+ };
+
+ enum class ReadOnlyFeatures {
+ SPARSE_SUPER_BLOCKS = 0x1,
+ FILES_64_BIT = 0x2,
+ BINARY_TREE_DIRECTORIES = 0x4,
+ };
+
+ typedef struct BlockGroupDescriptor{
+ uint32_t block_usage_bitmap;
+ uint32_t block_inode_bitmap;
+ uint32_t inode_table_address;
+ uint16_t free_blocks;
+ uint16_t free_inodes;
+ uint16_t directory_count;
+ uint8_t free[14];
+
+ } __attribute__((packed)) block_group_descriptor_t;
+
+ typedef struct Inode{
+ union {
+ uint16_t type_permissions;
+ struct {
+ uint16_t permissions : 12;
+ uint16_t type : 4;
+ };
+ };
+ uint16_t user_id;
+ uint32_t size_lower;
+ uint32_t last_access_time;
+ uint32_t creation_time;
+ uint32_t last_modification_time;
+ uint32_t deletion_time;
+ uint16_t group_id;
+ uint16_t hard_links;
+ uint32_t sectors_used;
+ uint32_t flags;
+ uint32_t os_1;
+ uint32_t block_pointers[12];
+ uint32_t l1_indirect;
+ uint32_t l2_indirect;
+ uint32_t l3_indirect;
+ uint32_t generation;
+ uint32_t extended_attribute; // File ACL
+ uint32_t size_upper; // Dir ACL
+ uint32_t os_2[3];
+ } __attribute__((packed)) inode_t;
+
+ enum class InodeType {
+ UNKNOWN,
+ FIFO = 0x1000,
+ CHARACTER_DEVICE = 0x2000,
+ DIRECTORY = 0x4000,
+ BLOCK_DEVICE = 0x6000,
+ FILE = 0x8000,
+ SYMBOLIC_LINK = 0xA000,
+ SOCKET = 0xC000,
+ };
+
+ enum class InodePermissions{
+ OTHER_EXECUTE = 0x1,
+ OTHER_WRITE = 0x2,
+ OTHER_READ = 0x4,
+ GROUP_EXECUTE = 0x8,
+ GROUP_WRITE = 0x10,
+ GROUP_READ = 0x20,
+ USER_EXECUTE = 0x40,
+ USER_WRITE = 0x80,
+ USER_READ = 0x100,
+ STICKY = 0x200,
+ GROUP_ID = 0x400,
+ USER_ID = 0x800,
+ };
+
+ enum class InodePermissionsDefaults{
+ FILE = 0x1A4,
+ DIRECTORY = 0x1ED,
+
+ };
+
+ enum class InodeFlags{
+ SECURE_DELETE = 0x1, // Zero out data on deletion
+ KEEP_DATA = 0x2,
+ FILE_COMPRESSION = 0x4,
+ SYNC_UPDATES = 0x8,
+ FILE_IMMUTABLE = 0x10,
+ APPEND_ONLY = 0x20,
+ DONT_DUMP = 0x40,
+ NO_LAST_ACCESS = 0x80,
+ HASH_INDEXED = 0x10000,
+ AFS_DIRECTORY = 0x20000,
+ JOURNAL_FILE_DATA = 0x40000,
+ };
+
+ // TODO: Also HURD, MASIX
+ typedef struct InodeOS2Linux{
+ uint8_t fragment;
+ uint8_t fragment_size;
+ uint16_t high_type_permissions;
+ uint16_t high_user_id;
+ uint16_t high_group_id;
+ uint32_t author_id; //0xFFFFFFFF = use user_id
+ } __attribute__((packed)) linux_os_2_t;
+
+ typedef struct DirectoryEntry{
+ uint32_t inode;
+ uint16_t size;
+ uint8_t name_length;
+ uint8_t type;
+ // Rest are name chars
+ } __attribute__((packed)) directory_entry_t;
+
+ enum class EntryType {
+ UNKNOWN,
+ FILE,
+ DIRECTORY,
+ CHARACTER_DEVICE,
+ BLOCK_DEVICE,
+ FIFO,
+ SOCKET,
+ SYMBOLIC_LINK
+ };
+
+ class Ext2Volume {
+
+ private:
+ common::Vector allocate_group_blocks(uint32_t block_group, uint32_t amount);
+ void free_group_blocks(uint32_t block_group, uint32_t amount, uint32_t start);
+
+
+ void write_back_block_groups() const;
+ void write_back_superblock();
+
+ public:
+ Ext2Volume(drivers::disk::Disk* disk, lba_t partition_offset);
+ ~Ext2Volume();
+
+ drivers::disk::Disk* disk;
+ lba_t partition_offset;
+
+ superblock_t superblock;
+ block_group_descriptor_t** block_groups;
+
+ size_t block_size;
+ uint32_t block_group_descriptor_table_block;
+ uint32_t block_group_descriptor_table_size;
+ uint32_t total_block_groups;
+ size_t pointers_per_block;
+ uint32_t inodes_per_block;
+ uint32_t sectors_per_block;
+
+ uint32_t blocks_per_inode_table;
+ uint32_t sectors_per_inode_table;
+
+ common::Spinlock ext2_lock;
+
+ void write_block(uint32_t block_num, common::buffer_t* buffer);
+ void write_inode(uint32_t inode_num, inode_t* inode);
+
+ [[nodiscard]] uint32_t create_inode(bool is_directory);
+ void free_inode(uint32_t inode);
+
+ void read_block(uint32_t block_num, common::buffer_t* buffer) const;
+ [[nodiscard]] inode_t read_inode(uint32_t inode_num) const;
+
+ [[nodiscard]] uint32_t allocate_block();
+ [[nodiscard]] common::Vector allocate_blocks(uint32_t amount);
+ [[nodiscard]] uint32_t bytes_to_blocks(size_t bytes) const;
+
+ void free_blocks(const common::Vector& blocks);
+
+
+ // TODO: free blocks
+ };
+
+ /**
+ * @class InodeHandler
+ * @brief Simplfies the management of an inode & its blocks
+ */
+ class InodeHandler {
+
+ private:
+ Ext2Volume* m_volume = nullptr;
+
+ void parse_indirect(uint32_t level, uint32_t block, common::buffer_t* buffer);
+ void write_indirect(uint32_t level, uint32_t& block, size_t& index);
+ void store_blocks(const common::Vector& blocks);
+
+ public:
+ InodeHandler(Ext2Volume* volume, uint32_t inode);
+ ~InodeHandler();
+
+ uint32_t inode_number;
+ inode_t inode;
+ common::Vector block_cache;
+
+ [[nodiscard]] size_t size() const;
+ void set_size(size_t size);
+ size_t grow(size_t amount, bool flush = true);
+
+ void save();
+
+ void free();
+
+ };
+
+ /**
+ * @class Ext2File
+ * @brief Handles the file operations on the ext2 filesystem
+ */
+ class Ext2File final : public File {
+ private:
+ Ext2Volume* m_volume;
+ InodeHandler m_inode;
+
+ public:
+ Ext2File(Ext2Volume* volume, uint32_t inode, const string& name);
+ ~Ext2File() final;
+
+ void write(const common::buffer_t* data, size_t amount) final;
+ void read(common::buffer_t* data, size_t amount) final;
+ void flush() final;
+ };
+
+ /**
+ * @class Ext2Directory
+ * @brief Handles the directory operations on the ext2 filesystem
+ */
+ class Ext2Directory final : public Directory {
+
+ private:
+ Ext2Volume* m_volume;
+ InodeHandler m_inode;
+
+ common::Vector m_entries;
+ common::Vector m_entry_names;
+
+ void write_entries();
+ directory_entry_t create_entry(const string& name, uint32_t inode, bool is_directory = false);
+
+ void parse_block(common::buffer_t* buffer);
+
+ void remove_entry(const string& name, bool is_directory, bool clear = true);
+ void rename_entry(const string& old_name, const string& new_name, bool is_directory);
+
+ public:
+ Ext2Directory(Ext2Volume* volume, uint32_t inode, const string& name);
+ ~Ext2Directory() final;
+
+ void read_from_disk() final;
+
+ File* create_file(const string& name) final;
+ void remove_file(const string& name) final;
+ void rename_file(const string& old_name, const string& new_name) final;
+
+ Directory* create_subdirectory(const string& name) final;
+ void remove_subdirectory(const string& name) final;
+ void rename_subdirectory(const string& old_name, const string& new_name) final;
+ };
+
+ /**
+ * @class Ext2FileSystem
+ * @brief Handles the ext2 filesystem operations
+ */
+ class Ext2FileSystem final : public FileSystem {
+ private:
+ Ext2Volume m_volume;
+
+ public:
+ Ext2FileSystem(drivers::disk::Disk* disk, uint32_t partition_offset);
+ ~Ext2FileSystem() final;
+ };
+
+ }
+ }
+ }
+}
+
+#endif // MAXOS_FILESYSTEM_EXT2_H
diff --git a/kernel/include/filesystem/format/fat32.h b/kernel/include/filesystem/format/fat32.h
new file mode 100644
index 00000000..9e27fb94
--- /dev/null
+++ b/kernel/include/filesystem/format/fat32.h
@@ -0,0 +1,292 @@
+//
+// Created by 98max on 1/01/2023.
+//
+
+#ifndef MAXOS_FILESYSTEM_FAT32_H
+#define MAXOS_FILESYSTEM_FAT32_H
+
+#include
+#include
+#include
+
+namespace MaxOS{
+ namespace filesystem{
+ namespace format{
+
+ // TODO: Revisit when I have the energy.
+ // BUG: Subdirectory seems to write to the disk this end but tools like
+ // fatcat complain the that the EOC isn't written (cluster 3037)
+ // - FAT32 Tests:
+ // - [x] Read subdirectories contents
+ // - [x] Read long path subdirectories contents
+ // - [ ] Create subdirectories
+ // - [ ] Create long path subdirectories
+ // - [ ] Delete subdirectories (need to add ability to free clusters first
+ // - [ ] Delete long path subdirectories
+ // - [ ] Rename directory
+ // - [ ] Rename file
+ // - [ ] Rename lfn directory
+ // - [ ] Rename lfn file
+ // - [x] Read files
+ // - [ ] Read large files
+ // - [x] Write files
+ // - [ ] Write large files
+ // - [ ] Create files
+ // - [ ] Delete files
+ // - [x] Read long path files
+ // - [ ] Create long path files
+ // - [ ] Delete long path files
+ // - [ ] Create files on a different mount point
+ // - [ ] Delete files on a different mount point
+ // - [ ] Read directories on a different mount point
+ // - [ ] Create directories on a different mount point
+ // - [ ] Stress test the filesystem: 1000s of files in a directory, long nested directories, long path files, etc
+
+ /**
+ * @struct BiosParameterBlock
+ * @brief Stores information about the FAT32 filesystem
+ */
+ typedef struct BiosParameterBlock32{
+
+ uint8_t jump[3];
+ uint8_t OEM_name[8];
+ uint16_t bytes_per_sector;
+ uint8_t sectors_per_cluster;
+ uint16_t reserved_sectors;
+ uint8_t table_copies;
+ uint16_t root_entries;
+ uint16_t total_sectors_16;
+ uint8_t media_type;
+ uint16_t fat_sector_count;
+ uint16_t sectors_per_track;
+ uint16_t head_count;
+ uint32_t hidden_sectors;
+ uint32_t total_sectors_32;
+
+ uint32_t table_size_32;
+ uint16_t extended_flags;
+ uint16_t fat_version;
+ uint32_t root_cluster;
+ uint16_t fat_info;
+ uint16_t backup_sector;
+ uint8_t reserved0[12];
+ uint8_t drive_number;
+ uint8_t reserved_1;
+ uint8_t boot_signature;
+ uint32_t uint_32;
+ uint8_t volume_label[11];
+ uint8_t file_system_type[8];
+
+ } __attribute__((packed)) bpb32_t;
+
+ /**
+ * @struct FileSystemInfo
+ * @brief Stores extra information about the FAT32 filesystem
+ */
+ typedef struct FSInfo
+ {
+ uint32_t lead_signature;
+ uint8_t reserved1[480];
+ uint32_t structure_signature;
+ uint32_t free_cluster_count;
+ uint32_t next_free_cluster;
+ uint8_t reserved2[12];
+ uint32_t trail_signature;
+ } __attribute__((packed)) fs_info_t;
+
+ /**
+ * @struct DirectoryEntry
+ * @brief Stores information about a file or directory
+ */
+ typedef struct DirectoryEntry{
+
+ uint8_t name[8];
+ uint8_t extension[3];
+ uint8_t attributes;
+ uint8_t reserved;
+
+ uint8_t creation_time_tenth;
+ uint16_t creation_time;
+ uint16_t creation_date;
+ uint16_t last_access_date;
+
+ uint16_t first_cluster_high;
+
+ uint16_t last_write_time;
+ uint16_t last_write_date;
+
+ uint16_t first_cluster_low;
+
+ uint32_t size;
+
+ } __attribute__((packed)) dir_entry_t;
+
+ enum class DirectoryEntryAttributes
+ {
+ FREE = 0x00,
+ READ_ONLY = 0x01,
+ HIDDEN = 0x02,
+ SYSTEM = 0x04,
+ VOLUME_ID = 0x08,
+ DIRECTORY = 0x10,
+ ARCHIVE = 0x20,
+ LONG_NAME = READ_ONLY | HIDDEN | SYSTEM | VOLUME_ID,
+ };
+
+ enum class DirectoryEntryType
+ {
+ LAST = 0x00,
+ FREE = 0xE5,
+ };
+
+ typedef struct LongFileNameEntry
+ {
+ uint8_t order;
+ uint16_t name1[5];
+ uint8_t attributes;
+ uint8_t type;
+ uint8_t checksum;
+ uint16_t name2[6];
+ uint16_t zero;
+ uint16_t name3[2];
+
+ } __attribute__((packed)) long_file_name_entry_t;
+
+ enum class ClusterState: uint32_t
+ {
+ FREE = 0x00000000,
+ BAD = 0x0FFFFFF7,
+ END_OF_CHAIN = 0xFFFFFFFF,
+ };
+
+ /**
+ * @class Fat32Volume
+ * @brief Handles the FAT table that stores the information about the files on the disk and operations on the disk
+ */
+ class Fat32Volume
+ {
+ public:
+ Fat32Volume(drivers::disk::Disk* disk, lba_t partition_offset);
+ ~Fat32Volume();
+
+ bpb32_t bpb;
+ fs_info_t fsinfo;
+
+ size_t fat_total_clusters;
+ lba_t fat_lba;
+ lba_t fat_info_lba;
+ lba_t fat_copies;
+
+ lba_t data_lba;
+ lba_t root_lba;
+
+ drivers::disk::Disk* disk;
+
+ uint32_t next_cluster(uint32_t cluster);
+ uint32_t set_next_cluster(uint32_t cluster, uint32_t next_cluster);
+ uint32_t find_free_cluster();
+
+ uint32_t allocate_cluster(uint32_t cluster);
+ uint32_t allocate_cluster(uint32_t cluster, size_t amount);
+
+ void free_cluster(uint32_t cluster);
+ void free_cluster(uint32_t cluster, size_t amount);
+ };
+
+ // Forward def
+ class Fat32Directory;
+
+ /**
+ * @class Fat32File
+ * @brief Handles the file operations on the FAT32 filesystem
+ */
+ class Fat32File final : public File
+ {
+
+ private:
+ Fat32Volume* m_volume;
+ Fat32Directory* m_parent_directory;
+
+ dir_entry_t* m_entry;
+ uint32_t m_first_cluster;
+
+ public:
+ Fat32File(Fat32Volume* volume, Fat32Directory* parent, dir_entry_t* info, const string& name);
+ ~Fat32File() final;
+
+ void write(const common::buffer_t* data, size_t amount) final;
+ void read(common::buffer_t* data, size_t amount) final;
+ void flush() final;
+
+ uint32_t first_cluster() const { return m_first_cluster; }
+ };
+
+ /**
+ * @class Fat32Directory
+ * @brief Handles the directory operations on the FAT32 filesystem
+ */
+ class Fat32Directory : public Directory
+ {
+ friend class Fat32File;
+
+ private:
+ Fat32Volume* m_volume;
+
+ lba_t m_first_cluster;
+ lba_t m_last_cluster;
+ size_t m_current_cluster_length = 0;
+
+ common::Vector m_entries;
+
+ dir_entry_t* create_entry(const string& name, bool is_directory);
+ void remove_entry(lba_t cluster, const string& name);
+ void read_all_entries();
+
+ int entry_index(lba_t cluster);
+ int find_free_entries(size_t amount);
+ int expand_directory(size_t amount);
+
+ static common::Vector to_long_filenames(string name);
+ static string parse_long_filename(long_file_name_entry_t* entry, const string& current);
+
+ protected:
+
+ void save_entry_to_disk(dir_entry_t* entry);
+ void update_entry_on_disk(int index);
+
+ public:
+ Fat32Directory(Fat32Volume* volume, lba_t cluster, const string& name);
+ ~Fat32Directory();
+
+ static const size_t MAX_NAME_LENGTH = 255;
+
+ void read_from_disk() final;
+
+ File* create_file(const string& name) final;
+ void remove_file(const string& name) final;
+
+ Directory* create_subdirectory(const string& name) final;
+ void remove_subdirectory(const string& name) final;
+
+ [[nodiscard]] lba_t first_cluster() const { return m_first_cluster; }
+ };
+
+ /**
+ * @class Fat32FileSystem
+ * @brief Handles the FAT32 filesystem operations
+ */
+ class Fat32FileSystem : public FileSystem
+ {
+ private:
+ Fat32Volume m_volume;
+
+ public:
+ Fat32FileSystem(drivers::disk::Disk* disk, uint32_t partition_offset);
+ ~Fat32FileSystem();
+ };
+
+ }
+ }
+}
+
+#endif //MAXOS_FILESYSTEM_FAT32_H
diff --git a/kernel/include/filesystem/msdospart.h b/kernel/include/filesystem/msdospart.h
deleted file mode 100644
index fcd9c682..00000000
--- a/kernel/include/filesystem/msdospart.h
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-// Created by 98max on 12/28/2022.
-//
-
-#ifndef MAXOS_FILESYSTEM_MSDOSPART_H
-#define MAXOS_FILESYSTEM_MSDOSPART_H
-
-#include "drivers/disk/ata.h"
-#include
-#include
-
-namespace MaxOS{
-
- namespace filesystem{
-
- /**
- * @struct PartitionTableEntry
- * @brief Stores information about a partition
- */
- struct PartitionTableEntry{
-
- uint8_t bootable; // 0x80 = bootable, 0x00 = not bootable
-
- uint8_t startHead;
- uint8_t startSector : 6;
- uint16_t startCylinder : 10;
-
- uint8_t partitionId;
-
- uint8_t endHead;
- uint8_t endSector : 6;
- uint16_t endCylinder : 10;
-
- uint32_t startLBA;
- uint32_t length;
-
- } __attribute__((packed));
-
- /**
- * @struct MasterBootRecord
- * @brief Stores information about the master boot record
- */
- struct MasterBootRecord{
-
- uint8_t bootloader[440];
- uint32_t diskSignature;
- uint16_t unused;
-
- PartitionTableEntry primaryPartition[4];
-
- uint16_t magicNumber;
-
- } __attribute__((packed));
-
- /**
- * @class MSDOSPartitionTable
- * @brief Reads the partition table of the hard drive
- */
- class MSDOSPartitionTable{
- public:
- static void read_partitions(drivers::disk::AdvancedTechnologyAttachment *hd);
-
- };
- }
-}
-
-#endif //MAXOS_FILESYSTEM_MSDOSPART_H
diff --git a/kernel/include/filesystem/partition/msdos.h b/kernel/include/filesystem/partition/msdos.h
new file mode 100644
index 00000000..96fed8f9
--- /dev/null
+++ b/kernel/include/filesystem/partition/msdos.h
@@ -0,0 +1,350 @@
+//
+// Created by Max Tyson on 18/04/2025.
+//
+
+#ifndef MAXOS_FILESYSTEM_PARTITION_MSDOS_H
+#define MAXOS_FILESYSTEM_PARTITION_MSDOS_H
+
+#include
+#include
+#include
+#include
+#include
+
+namespace MaxOS{
+
+ namespace filesystem{
+
+ namespace partition{
+
+
+ /// Credit: http://www.osdever.net/documents/pdf/partitiontypes.pdf
+ enum class PartitionType {
+ EMPTY, // 0x00
+ FAT12, // 0x01
+ XENIX_ROOT, // 0x02
+ XENIX_USR, // 0x03
+ FAT16, // 0x04
+ EXTENDED, // 0x05
+ FAT16_32MB, // 0x06
+ NTFS, // 0x07
+ QNX_QNY, // 0x08
+ AIX_DATA, // 0x09
+ OS2_BOOT_MANAGER, // 0x0A
+ FAT32, // 0x0B
+ FAT32_LBA, // 0x0C
+ UNUSED_1, // 0x0D
+ FAT16_LBA, // 0x0E
+ EXTENDED_LBA, // 0x0F
+ OPUS, // 0x10
+ FAT12_HIDDEN, // 0x11
+ COMPAQ, // 0x12
+ UNUSED_2, // 0x13
+ FAT16_HIDDEN, // 0x14
+ UNUSED_3, // 0x15
+ FAT16_32MB_HIDDEN, // 0x16
+ IFS_HIDDEN, // 0x17
+ AST_SMART_SLEEP, // 0x18
+ UNUSED_4, // 0x19
+ UNUSED_5, // 0x1A
+ FAT32_HIDDEN, // 0x1B
+ FAT32_LBA_HIDDEN, // 0x1C
+ UNUSED_6, // 0x1D
+ FAT16_LBA_HIDDEN, // 0x1E
+
+ UNUSED_7, // 0x1F
+ UNUSED_8, // 0x20
+ RESERVED_1, // 0x21
+ UNUSED_10, // 0x22
+ RESERVED_2, // 0x23
+ NEC_DOS, // 0x24
+ UNUSED_11, // 0x25
+ RESERVED_3, // 0x26
+
+ // 0x27 - 0x30: unassigned
+ UNUSED_12, // 0x27
+ UNUSED_13, // 0x28
+ UNUSED_14, // 0x29
+ UNUSED_15, // 0x2A
+ UNUSED_16, // 0x2B
+ UNUSED_17, // 0x2C
+ UNUSED_18, // 0x2D
+ UNUSED_19, // 0x2E
+ UNUSED_20, // 0x2F
+ UNUSED_21, // 0x30
+
+ RESERVED_4, // 0x31
+ NOS, // 0x32
+ RESERVED_5, // 0x33
+ RESERVED_6, // 0x34
+ JFS, // 0x35
+ RESERVED_7, // 0x36
+ UNUSED_22, // 0x37
+ THEOS_3_2, // 0x38
+ PLAN9, // 0x39
+ THEOS_4_4GB, // 0x3A
+ THEOS_4_EXTENDED, // 0x3B
+ PARTITIONMAGIC_RECOVERY, // 0x3C
+ HIDDEN_NETWARE, // 0x3D
+ UNUSED_23, // 0x3E
+ UNUSED_24, // 0x3F
+
+ VENIX, // 0x40
+ LINUX_MINIX, // 0x41
+ LINUX_SWAP, // 0x42
+ LINUX_NATIVE, // 0x43
+ GOBACK, // 0x44
+ BOOT_US, // 0x45
+ EUMEL_ELAN_46, // 0x46
+ EUMEL_ELAN_47, // 0x47
+ EUMEL_ELAN_48, // 0x48
+ UNUSED_25, // 0x49
+ ADAOS, // 0x4A
+ UNUSED_26, // 0x4B
+ OBERON, // 0x4C
+ QNX4, // 0x4D
+ QNX4_SECOND, // 0x4E
+ QNX4_THIRD, // 0x4F
+
+ ONTRACK_DM, // 0x50
+ ONTRACK_DM_RW, // 0x51
+ CPM, // 0x52
+ DISK_MANAGER_AUX3, // 0x53
+ DISK_MANAGER_DDO, // 0x54
+ EZ_DRIVE, // 0x55
+ GOLDEN_BOW, // 0x56
+ DRIVE_PRO, // 0x57
+
+ UNUSED_27, // 0x58
+ UNUSED_28, // 0x59
+ UNUSED_29, // 0x5A
+ UNUSED_30, // 0x5B
+ PRIAM_EDISK, // 0x5C
+ UNUSED_31, // 0x5D
+ UNUSED_32, // 0x5E
+ UNUSED_33, // 0x5F
+
+ UNUSED_34, // 0x60
+ SPEEDSTOR, // 0x61
+ UNUSED_35, // 0x62
+ UNIX, // 0x63
+ PC_ARMOUR, // 0x64
+ NOVELL_NETWARE386, // 0x65
+ NOVELL_SMS, // 0x66
+ NOVELL, // 0x67
+ NOVELL_OLD, // 0x68
+ NOVELL_NETWARE_NSS, // 0x69
+
+ UNUSED_36, // 0x6A
+ UNUSED_37, // 0x6B
+ UNUSED_38, // 0x6C
+ UNUSED_39, // 0x6D
+ UNUSED_40, // 0x6E
+ UNUSED_41, // 0x6F
+
+ DISKSECURE, // 0x70
+ RESERVED_8, // 0x71
+ UNUSED_42, // 0x72
+ RESERVED_9, // 0x73
+ SCRAMDISK, // 0x74
+ IBM_PCIX, // 0x75
+ RESERVED_10, // 0x76
+ M2FS, // 0x77
+ XOSL_FS, // 0x78
+ UNUSED_43, // 0x79
+ UNUSED_44, // 0x7A
+ UNUSED_45, // 0x7B
+ UNUSED_46, // 0x7C
+ UNUSED_47, // 0x7D
+ UNUSED_48, // 0x7E
+ UNUSED_49, // 0x7F
+
+ MINIX, // 0x80
+ MINIX2, // 0x81
+ LINUX_SWAP_ALT, // 0x82
+ LINUX_EXT2, // 0x83
+ HIBERNATION, // 0x84
+ LINUX_EXTENDED, // 0x85
+ LINUX_RAID, // 0x86
+ NTFS_VOLUME_SET, // 0x87
+ UNUSED_50, // 0x88
+ UNUSED_51, // 0x89
+ LINUX_KERNEL, // 0x8A
+ FAULT_TOLERANT_FAT32, // 0x8B
+ FT_FAT32_LBA, // 0x8C
+ FREEFDISK_FAT12, // 0x8D
+ LINUX_LVM, // 0x8E
+ UNUSED_52, // 0x8F
+ FREEFDISK_FAT16, // 0x90
+ FREEFDISK_EXTENDED, // 0x91
+ FREEFDISK_FAT16_LARGE, // 0x92
+ HIDDEN_LINUX_NATIVE, // 0x93
+ AMOEBA_BAD_BLOCK, // 0x94
+ MIT_EXOPC, // 0x95
+ UNUSED_53, // 0x96
+ FREEFDISK_FAT32, // 0x97
+ FREEFDISK_FAT32_LBA, // 0x98
+ DCE376, // 0x99
+ FREEFDISK_FAT16_LBA, // 0x9A
+ FREEFDISK_EXTENDED_LBA,// 0x9B
+
+ UNUSED_54, // 0x9C
+ UNUSED_55, // 0x9D
+ UNUSED_56, // 0x9E
+
+ BSD_OS, // 0x9F
+ LAPTOP_HIBERNATION, // 0xA0
+ HP_VOLUME_EXPANSION, // 0xA1
+ UNUSED_57, // 0xA2
+ RESERVED_11, // 0xA3
+ RESERVED_12, // 0xA4
+ BSD_386, // 0xA5
+ OPENBSD, // 0xA6
+ NEXTSTEP, // 0xA7
+ MAC_OS_X, // 0xA8
+ NETBSD, // 0xA9
+ OLIVETTI_SERVICE, // 0xAA
+ MAC_OS_X_BOOT, // 0xAB
+ UNUSED_58, // 0xAC
+ UNUSED_59, // 0xAD
+ SHAGOS, // 0xAE
+ SHAGOS_SWAP, // 0xAF
+ BOOTSTAR, // 0xB0
+
+ RESERVED_13, // 0xB1
+ UNUSED_60, // 0xB2
+ RESERVED_14, // 0xB3
+ RESERVED_15, // 0xB4
+ UNUSED_61, // 0xB5
+ RESERVED_16, // 0xB6
+
+ BSDI_BSD386_FS, // 0xB7
+ BSDI_BSD386_SWAP, // 0xB8
+ UNUSED_62, // 0xB9
+ UNUSED_63, // 0xBA
+ BOOT_WIZARD_HIDDEN, // 0xBB
+ UNUSED_64, // 0xBC
+ UNUSED_65, // 0xBD
+ SOLARIS8_BOOT, // 0xBE
+ UNUSED_66, // 0xBF
+ CTOS, // 0xC0
+ DRDOS_FAT12, // 0xC1
+ RESERVED_17, // 0xC2
+ HIDDEN_LINUX_SWAP, // 0xC3
+ DRDOS_FAT16, // 0xC4
+ DRDOS_EXTENDED, // 0xC5
+ DRDOS_FAT16_LARGE, // 0xC6
+ NTFS_CORRUPT, // 0xC7
+
+ UNUSED_67, // 0xC8
+ UNUSED_68, // 0xC9
+ UNUSED_69, // 0xCA
+
+ DRDOS_FAT32, // 0xCB
+ DRDOS_FAT32_LBA, // 0xCC
+ CTOS_MEMDUMP, // 0xCD
+ DRDOS_FAT16_LBA, // 0xCE
+ UNUSED_70, // 0xCF
+ REAL32_SECURE_BIG, // 0xD0
+ OLD_MULTIUSER_DOS_FAT12,// 0xD1
+ UNUSED_71, // 0xD2
+ UNUSED_72, // 0xD3
+ OLD_MULTIUSER_DOS_FAT16,// 0xD4
+ OLD_MULTIUSER_DOS_EXTENDED,// 0xD5
+ OLD_MULTIUSER_DOS_FAT16_LARGE,// 0xD6
+ UNUSED_73, // 0xD7
+ CPM86, // 0xD8
+ UNUSED_74, // 0xD9
+ NON_FS_DATA, // 0xDA
+ DIGITAL_RESEARCH_CPM, // 0xDB
+ UNUSED_75, // 0xDC
+ HIDDEN_CTOS_MEMDUMP, // 0xDD
+ DELL_POWEREDGE, // 0xDE
+ DGUX, // 0xDF
+ STM_AVFS, // 0xE0
+ SPEEDSTOR_FAT_EXTENDED,// 0xE1
+ UNUSED_76, // 0xE2
+ SPEEDSTOR_RO, // 0xE3
+ SPEEDSTOR_EXTENDED, // 0xE4
+ TANDY_DOS, // 0xE5
+
+ RESERVED_18, // 0xE6
+ UNUSED_77, // 0xE7
+ UNUSED_78, // 0xE8
+ UNUSED_79, // 0xE9
+
+ BEFS, // 0xEA
+ SPRYTIX, // 0xEB
+ EFI_PROTECTIVE, // 0xEE
+ EFI_SYSTEM, // 0xEF
+ LINUX_PA_RISC, // 0xF0
+ SPEEDSTOR_2, // 0xF1
+ DOS_3_3_SECONDARY, // 0xF2
+ RESERVED_19, // 0xF3
+ SPEEDSTOR_LARGE, // 0xF4
+ PROLOGUE_MULTI, // 0xF5
+ RESERVED_20, // 0xF6
+ UNUSED_80, // 0xF7
+ UNUSED_81, // 0xF8
+ UNUSED_82, // 0xF9
+ BOCHS, // 0xFA
+ VMFS, // 0xFB
+ VMWARE_SWAP, // 0xFC
+ LINUX_RAID_AUTO, // 0xFD
+ NT_HIDDEN, // 0xFE
+ XENIX_BAD_BLOCK // 0xFF
+ };
+
+ /**
+ * @struct PartitionTableEntry
+ * @brief Stores information about a partition
+ */
+ struct PartitionTableEntry{
+
+ uint8_t bootable; // 0x80 = bootable, 0x00 = not bootable
+
+ uint8_t start_head;
+ uint8_t start_sector : 6;
+ uint16_t start_cylinder : 10;
+
+ uint8_t type;
+
+ uint8_t end_head;
+ uint8_t end_sector : 6;
+ uint16_t end_cylinder : 10;
+
+ uint32_t start_LBA;
+ uint32_t length;
+
+ } __attribute__((packed));
+
+ /**
+ * @struct MasterBootRecord
+ * @brief Stores information about the master boot record
+ */
+ struct MasterBootRecord{
+
+ uint8_t bootloader[440];
+ uint32_t disk_signature;
+ uint16_t unused;
+
+ PartitionTableEntry primary_partition[4];
+
+ uint16_t magic;
+
+ } __attribute__((packed));
+
+
+ class MSDOSPartition
+ {
+ public:
+ static void mount_partitions(drivers::disk::Disk* disk);
+ };
+
+
+ // TODO: Abstract some of this into a base class and use it for GPT and other partition tables
+ }
+ }
+}
+
+#endif //MSDOS_H
diff --git a/kernel/include/filesystem/path.h b/kernel/include/filesystem/path.h
new file mode 100644
index 00000000..e612f0d8
--- /dev/null
+++ b/kernel/include/filesystem/path.h
@@ -0,0 +1,39 @@
+//
+// Created by 98max on 9/2/2025.
+//
+
+#ifndef MAXOS_FILESYSTEM_PATH_H
+#define MAXOS_FILESYSTEM_PATH_H
+
+#include
+
+namespace MaxOS {
+
+ namespace filesystem {
+
+ /**
+ * @class Path
+ * @brief Handles file & directory paths
+ */
+ class Path
+ {
+ public:
+ static bool valid(string path);
+ static bool is_file(const string& path);
+
+ static string file_name(string path);
+ static string file_extension(string path);
+ static string file_path(string path);
+
+ static string top_directory(string path);
+ static string parent_directory(string path);
+
+ static string absolute_path(string path);
+ static string join_path(string base, string extended);
+ };
+
+
+ }
+}
+
+#endif //MAXOS_FILESYSTEM_PATH_H
diff --git a/kernel/include/filesystem/vfs.h b/kernel/include/filesystem/vfs.h
new file mode 100644
index 00000000..a371f052
--- /dev/null
+++ b/kernel/include/filesystem/vfs.h
@@ -0,0 +1,63 @@
+//
+// Created by Max Tyson on 20/04/2025.
+//
+
+#ifndef MAXOS_FILESYSTEM_VFS_H
+#define MAXOS_FILESYSTEM_VFS_H
+
+#include
+#include
+#include
+
+namespace MaxOS{
+
+ namespace filesystem{
+
+ class VirtualFileSystem{
+
+ private:
+ common::Map filesystems;
+ inline static VirtualFileSystem* s_current_file_system = nullptr;
+
+ public:
+ VirtualFileSystem();
+ ~VirtualFileSystem();
+
+ static VirtualFileSystem* current_file_system();
+
+ void mount_filesystem(FileSystem* filesystem);
+ void mount_filesystem(FileSystem* filesystem, const string& mount_point);
+ void unmount_filesystem(FileSystem* filesystem);
+ void unmount_filesystem(const string& mount_point);
+ void unmount_all();
+
+ Directory* root_directory();
+ FileSystem* root_filesystem();
+
+ FileSystem* get_filesystem(const string& mount_point);
+ FileSystem* find_filesystem(string path);
+ string get_relative_path(FileSystem* filesystem, string path);
+
+ Directory* open_directory(const string& path);
+ static Directory* open_directory(Directory* parent, const string& name);
+
+ Directory* create_directory(string path);
+ static Directory* create_directory(Directory* parent, const string& name);
+
+ void delete_directory(string path);
+ static void delete_directory(Directory* parent, const string& name);
+ static void delete_directory(Directory* parent, Directory* directory);
+
+ File* create_file(const string& path);
+ static File* create_file(Directory* parent, const string& name);
+
+ File* open_file(const string& path, size_t offset = 0);
+ static File* open_file(Directory* parent, const string& name, size_t offset = 0);
+
+ void delete_file(const string& path);
+ static void delete_file(Directory* parent, const string& name);
+ };
+ }
+}
+
+#endif //MAXOS_FILESYSTEM_VFS_H
diff --git a/kernel/include/filesystem/vfsresource.h b/kernel/include/filesystem/vfsresource.h
new file mode 100644
index 00000000..ede19f8a
--- /dev/null
+++ b/kernel/include/filesystem/vfsresource.h
@@ -0,0 +1,72 @@
+//
+// Created by 98max on 9/1/2025.
+//
+
+#ifndef MAXOS_FILESYSTEM_VFSRESOURCE_H
+#define MAXOS_FILESYSTEM_VFSRESOURCE_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace MaxOS {
+
+ namespace filesystem {
+
+ class FileResource final : public processes::Resource{
+
+ public:
+ FileResource(const string& name, size_t flags, processes::resource_type_t type);
+ ~FileResource() final;
+
+ File* file;
+
+ int read(void* buffer, size_t size, size_t flags) final;
+ int write(const void* buffer, size_t size, size_t flags) final;
+
+ };
+
+ class DirectoryResource final : public processes::Resource{
+
+ private:
+
+ void write_entries(const void* buffer, size_t size) const;
+ [[nodiscard]] size_t entries_size() const;
+
+ public:
+
+ DirectoryResource(const string& name, size_t flags, processes::resource_type_t type);
+ ~DirectoryResource() final;
+
+ Directory* directory;
+
+ int read(void* buffer, size_t size, size_t flags) final;
+ int write(const void* buffer, size_t size, size_t flags) final;
+
+ };
+
+ class VFSResourceRegistry : processes::BaseResourceRegistry{
+
+ private:
+ VirtualFileSystem* m_vfs;
+
+ processes::Resource* open_as_resource(const string& name, Directory* directory);
+ processes::Resource* open_as_resource(const string& name, File* file);
+
+ public:
+
+ explicit VFSResourceRegistry(VirtualFileSystem* vfs);
+ ~VFSResourceRegistry();
+
+ processes::Resource* get_resource(const string& name) final;
+ processes::Resource* create_resource(const string& name, size_t flags) final;
+
+ };
+
+ }
+}
+
+#endif //MAXOS_FILESYSTEM_VFSRESOURCE_H
diff --git a/kernel/include/hardwarecommunication/pci.h b/kernel/include/hardwarecommunication/pci.h
index d4faf211..858b4fe0 100644
--- a/kernel/include/hardwarecommunication/pci.h
+++ b/kernel/include/hardwarecommunication/pci.h
@@ -82,8 +82,8 @@ namespace MaxOS
Port32Bit m_command_port;
// I/O
- uint32_t read(uint16_t bus, uint16_t device, uint16_t function, uint32_t registeroffset);
- void write(uint16_t bus, uint16_t device, uint16_t function, uint32_t registeroffset, uint32_t value);
+ uint32_t read(uint16_t bus, uint16_t device, uint16_t function, uint32_t register_offset);
+ void write(uint16_t bus, uint16_t device, uint16_t function, uint32_t register_offset, uint32_t value);
// Device
PeripheralComponentInterconnectDeviceDescriptor get_device_descriptor(uint16_t bus, uint16_t device, uint16_t function);
diff --git a/kernel/include/memory/physical.h b/kernel/include/memory/physical.h
index ba4f8e11..bb98180c 100644
--- a/kernel/include/memory/physical.h
+++ b/kernel/include/memory/physical.h
@@ -100,7 +100,7 @@ namespace MaxOS {
// Table Management
pml_t* get_or_create_table(pml_t* table, size_t index, size_t flags);
pml_t* get_and_create_table(pml_t* parent_table, uint64_t table_index, pml_t* table);
- pte_t create_page_table_entry(uintptr_t address, size_t flags);
+ pte_t create_page_table_entry(uintptr_t address, size_t flags) const;
static uint64_t physical_address_of_entry(pte_t* entry);
pte_t* get_entry(virtual_address_t* virtual_address, pml_t* pml4_root);
diff --git a/kernel/include/processes/elf.h b/kernel/include/processes/elf.h
index d0ff7891..8c412519 100644
--- a/kernel/include/processes/elf.h
+++ b/kernel/include/processes/elf.h
@@ -158,7 +158,7 @@ namespace MaxOS
static char elf_magic[4];
- void load_program_headers();
+ void load_program_headers() const;
public:
@@ -166,11 +166,11 @@ namespace MaxOS
~Elf64();
void load();
- bool is_valid();
+ bool is_valid() const;
[[nodiscard]] elf_64_header_t* header() const;
- elf_64_program_header_t* get_program_header(size_t index);
- elf_64_section_header_t* get_section_header(size_t index);
+ elf_64_program_header_t* get_program_header(size_t index) const;
+ elf_64_section_header_t* get_section_header(size_t index) const;
static uint64_t to_vmm_flags(uint32_t type);
diff --git a/kernel/include/processes/ipc.h b/kernel/include/processes/ipc.h
index 4a82dc09..b4a62dbe 100644
--- a/kernel/include/processes/ipc.h
+++ b/kernel/include/processes/ipc.h
@@ -9,92 +9,52 @@
#include
#include
#include
+#include
#include
#include
#include
-
+#include
namespace MaxOS {
namespace processes {
- //TODO: LibIPC
-
- class SharedMemory{
+ class SharedMemory final : public Resource {
private:
uintptr_t m_physical_address;
size_t m_size;
- uint64_t m_owner_pid;
+ common::Map m_mappings;
public:
- SharedMemory(string name, size_t size);
- ~SharedMemory();
+ SharedMemory(const string& name, size_t size, resource_type_t type);
+ ~SharedMemory() final;
- string* name;
+ string name;
uint64_t use_count = 1;
+ void open(size_t flags) final;
+ void close(size_t flags) final;
+
+ int read(void* buffer, size_t size, size_t flags) final;
+
[[nodiscard]] uintptr_t physical_address() const;
[[nodiscard]] size_t size() const;
};
-
- typedef struct SharedMessage{
- void* message_buffer;
- size_t message_size;
- uintptr_t next_message;
- } ipc_message_t;
-
- typedef struct SharedMessageQueue{
- ipc_message_t* messages;
- } ipc_message_queue_t;
-
- class SharedMessageEndpoint{
+ class SharedMessageEndpoint final : public Resource{
private:
- ipc_message_queue_t* m_queue = nullptr;
- uint64_t m_owner_pid;
+ common::Vector m_queue {};
common::Spinlock m_message_lock;
public:
- SharedMessageEndpoint(string name);
- ~SharedMessageEndpoint();
-
- string* name;
- [[nodiscard]] ipc_message_queue_t* queue() const;
+ SharedMessageEndpoint(const string& name, size_t size, resource_type_t type);
+ ~SharedMessageEndpoint() final;
- void queue_message(void* message, size_t size);
- [[nodiscard]] bool owned_by_current_process() const;
+ int read(void* buffer, size_t size, size_t flags) final;
+ int write(const void* buffer, size_t size, size_t flags) final;
};
-
- /**
- * @class InterProcessCommunicationManager (IPC)
- * @brief Manages the Inter-Process Communication between processes via shared memory and message passing
- */
- class InterProcessCommunicationManager {
-
- common::Vector m_shared_memory_blocks;
- common::Vector m_message_endpoints;
-
- common::Spinlock m_lock;
-
- public:
-
- InterProcessCommunicationManager();
- ~InterProcessCommunicationManager();
-
- SharedMemory* alloc_shared_memory(size_t size, string name);
- SharedMemory* get_shared_memory(const string& name);
- void free_shared_memory(const string& name);
- void free_shared_memory(uintptr_t physical_address);
- void free_shared_memory(SharedMemory* block);
-
- SharedMessageEndpoint* create_message_endpoint(const string& name);
- SharedMessageEndpoint* get_message_endpoint(const string& name);
- void free_message_endpoint(const string& name);
- static void free_message_endpoint(SharedMessageEndpoint* endpoint);
- };
-
}
}
diff --git a/kernel/include/processes/process.h b/kernel/include/processes/process.h
index e98d5cf0..a0903c19 100644
--- a/kernel/include/processes/process.h
+++ b/kernel/include/processes/process.h
@@ -7,12 +7,14 @@
#include
#include
+#include
#include
#include
#include
#include
#include
#include
+#include
namespace MaxOS
@@ -67,8 +69,6 @@ namespace MaxOS
void save_sse_state();
void restore_sse_state();
-
-
};
/**
@@ -79,8 +79,6 @@ namespace MaxOS
{
private:
-
- common::Vector m_resource_ids;
common::Vector m_threads;
uint64_t m_pid = 0;
@@ -102,7 +100,10 @@ namespace MaxOS
bool is_kernel;
string name;
+ string working_directory = "/";
+
memory::MemoryManager* memory_manager = nullptr;
+ ResourceManager resource_manager;
};
diff --git a/kernel/include/processes/resource.h b/kernel/include/processes/resource.h
new file mode 100644
index 00000000..897ff5d4
--- /dev/null
+++ b/kernel/include/processes/resource.h
@@ -0,0 +1,123 @@
+//
+// Created by 98max on 8/26/2025.
+//
+
+#ifndef MAXOS_PROCESSES_RESOURCE_H
+#define MAXOS_PROCESSES_RESOURCE_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace MaxOS {
+ namespace processes {
+
+ typedef ::syscore::ResourceType resource_type_t;
+ typedef ::syscore::ResourceErrorBase resource_error_base_t;
+
+ class Resource {
+
+ private:
+ string m_name;
+ resource_type_t m_type;
+
+ public:
+
+ Resource(const string& name, size_t flags, resource_type_t type);
+ virtual ~Resource();
+
+ string name();
+ resource_type_t type();
+
+ virtual void open(size_t flags);
+ virtual void close(size_t flags);
+
+ virtual int read(void* buffer, size_t size, size_t flags);
+ virtual int write(const void* buffer, size_t size, size_t flags);
+ };
+
+ class BaseResourceRegistry{
+
+ protected:
+ common::Map m_resources;
+ common::Map m_resource_uses;
+
+ resource_type_t m_type;
+
+ public:
+ explicit BaseResourceRegistry(resource_type_t type);
+ ~BaseResourceRegistry();
+
+ resource_type_t type();
+
+ virtual Resource* get_resource(const string& name);
+ virtual bool register_resource(Resource* resource);
+
+ virtual void close_resource(Resource* resource, size_t flags);
+ virtual Resource* create_resource(const string& name, size_t flags);
+ };
+
+ template class ResourceRegistry : public BaseResourceRegistry{
+
+ public:
+ explicit ResourceRegistry(resource_type_t type);
+ ~ResourceRegistry() = default;
+
+ Resource* create_resource(const string& name, size_t flags) override {
+
+ auto resource = new Type(name, flags, type());
+
+ // Creation failed
+ if(!register_resource(resource)){
+ delete resource;
+ return nullptr;
+ }
+
+ return resource;
+ }
+ };
+
+ template ResourceRegistry::ResourceRegistry(resource_type_t type):BaseResourceRegistry(type) {}
+
+ class GlobalResourceRegistry{
+
+ private:
+ common::Map m_registries;
+ inline static GlobalResourceRegistry* s_current;
+
+ public:
+ GlobalResourceRegistry();
+ ~GlobalResourceRegistry();
+
+ static BaseResourceRegistry* get_registry(resource_type_t type);
+
+ static void add_registry(resource_type_t type, BaseResourceRegistry* registry);
+ static void remove_registry(BaseResourceRegistry* registry);
+ };
+
+ class ResourceManager{
+
+ private:
+ common::Map m_resources;
+
+ uint64_t m_next_handle = 1;
+
+ public:
+ ResourceManager();
+ ~ResourceManager();
+
+ common::Map resources();
+
+ uint64_t open_resource(resource_type_t type, const string& name, size_t flags);
+ void close_resource(uint64_t handle, size_t flags);
+
+ Resource* get_resource(uint64_t handle);
+ Resource* get_resource(const string& name);
+ };
+ }
+}
+
+#endif //MAXOS_PROCESSES_RESOURCE_H
diff --git a/kernel/include/processes/scheduler.h b/kernel/include/processes/scheduler.h
index a8aaf5aa..614b2382 100644
--- a/kernel/include/processes/scheduler.h
+++ b/kernel/include/processes/scheduler.h
@@ -36,13 +36,14 @@ namespace MaxOS{
inline static Scheduler* s_instance = nullptr;
static const uint64_t s_ticks_per_event = { 3 };
- InterProcessCommunicationManager* m_ipc;
+ GlobalResourceRegistry m_global_resource_registry = {};
+ ResourceRegistry m_shared_memory_registry;
+ ResourceRegistry m_shared_messages_registry;
public:
Scheduler(system::Multiboot& multiboot);
~Scheduler();
-
system::cpu_status_t* handle_interrupt(system::cpu_status_t* status) final;
system::cpu_status_t* schedule(system::cpu_status_t* status);
@@ -59,7 +60,6 @@ namespace MaxOS{
static Process* get_process(uint64_t pid);
static Thread* current_thread();
static Thread* get_thread(uint64_t tid);
- static InterProcessCommunicationManager* scheduler_ipc();
[[nodiscard]] uint64_t ticks() const;
diff --git a/kernel/include/runtime/ubsan.h b/kernel/include/runtime/ubsan.h
index e41c5ef2..1e1198ee 100644
--- a/kernel/include/runtime/ubsan.h
+++ b/kernel/include/runtime/ubsan.h
@@ -77,6 +77,12 @@ namespace MaxOS {
"cast to virtual base of",
};
+
+ typedef struct vla_bound_not_positive_info{
+ source_location_t location;
+ type_descriptor_t* type;
+ } vla_bound_not_positive_info_t;
+
/**
* @class UBSanHandler
* @brief Handles undefined behaviour sanitizer
diff --git a/kernel/include/system/syscalls.h b/kernel/include/system/syscalls.h
index 8b712009..fe437280 100644
--- a/kernel/include/system/syscalls.h
+++ b/kernel/include/system/syscalls.h
@@ -12,6 +12,7 @@
#include
#include
#include
+#include // TODO: Rename / make clear that this references the system lib
namespace MaxOS{
@@ -20,22 +21,6 @@ namespace MaxOS{
// Forward declaration
class SyscallManager;
- /// DO NOT REARRANGE ONLY APPEND TO
- enum SyscallType{
- CLOSE_PROCESS,
- KLOG,
- CREATE_SHARED_MEMORY,
- OPEN_SHARED_MEMORY,
- ALLOCATE_MEMORY,
- FREE_MEMORY,
- CREATE_IPC_ENDPOINT,
- SEND_IPC_MESSAGE,
- REMOVE_IPC_ENDPOINT,
- THREAD_YIELD,
- THREAD_SLEEP,
- THREAD_CLOSE,
- };
-
typedef struct SyscallArguments{
uint64_t arg0;
uint64_t arg1;
@@ -44,7 +29,7 @@ namespace MaxOS{
uint64_t arg4;
uint64_t arg5;
uint64_t return_value;
- system::cpu_status_t* return_state;
+ cpu_status_t* return_state;
} syscall_args_t;
// Could use a class based response but a single class might want multiple handlers e.g. fs
@@ -65,25 +50,24 @@ namespace MaxOS{
SyscallManager();
~SyscallManager();
- system::cpu_status_t* handle_interrupt(system::cpu_status_t* esp) final;
-
- void set_syscall_handler(uint8_t syscall, syscall_func_t handler);
- void remove_syscall_handler(uint8_t syscall);
-
-
- // Syscalls
- static system::syscall_args_t* syscall_close_process(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_klog(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_create_shared_memory(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_open_shared_memory(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_allocate_memory(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_free_memory(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_create_ipc_endpoint(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_send_ipc_message(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_remove_ipc_endpoint(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_thread_yield(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_thread_sleep(system::syscall_args_t* args);
- static system::syscall_args_t* syscall_thread_close(system::syscall_args_t* args);
+ cpu_status_t* handle_interrupt(cpu_status_t* esp) final;
+
+ void set_syscall_handler(::syscore::SyscallType syscall, syscall_func_t handler);
+ void remove_syscall_handler(::syscore::SyscallType syscall);
+
+ // Syscalls (TODO: Very c style, should be made class based that automatically registers)
+ static syscall_args_t* syscall_close_process(syscall_args_t* args);
+ static syscall_args_t* syscall_klog(syscall_args_t* args);
+ static syscall_args_t* syscall_allocate_memory(syscall_args_t* args);
+ static syscall_args_t* syscall_free_memory(syscall_args_t* args);
+ static syscall_args_t* syscall_resource_create(syscall_args_t* args);
+ static syscall_args_t* syscall_resource_open(syscall_args_t* args);
+ static syscall_args_t* syscall_resource_close(syscall_args_t* args);
+ static syscall_args_t* syscall_resource_write(syscall_args_t* args);
+ static syscall_args_t* syscall_resource_read(syscall_args_t* args);
+ static syscall_args_t* syscall_thread_yield(syscall_args_t* args);
+ static syscall_args_t* syscall_thread_sleep(syscall_args_t* args);
+ static syscall_args_t* syscall_thread_close(syscall_args_t* args);
};
}
diff --git a/kernel/src/asm/interruptstubs.s b/kernel/src/asm/interrupts.s
similarity index 100%
rename from kernel/src/asm/interruptstubs.s
rename to kernel/src/asm/interrupts.s
diff --git a/kernel/src/asm/loader.s b/kernel/src/asm/loader.s
index 4fd42a69..db13be80 100644
--- a/kernel/src/asm/loader.s
+++ b/kernel/src/asm/loader.s
@@ -1,8 +1,8 @@
%define KERNEL_VIRTUAL_ADDR 0xFFFFFFFF80000000
%define PAGE_SIZE 0x1000
%define FLAGS 0b10 | 1
-%define LOOP_LIMIT 1024
-%define PD_LOOP_LIMIT 2
+%define LOOP_LIMIT 2048
+%define PD_LOOP_LIMIT 4
global p2_table
@@ -27,17 +27,7 @@ start:
; Setup lower half of the stack
mov esp, stack.top - KERNEL_VIRTUAL_ADDR
- ; Map the kernel into the higher half
- mov eax, p3_table_hh - KERNEL_VIRTUAL_ADDR
- or eax, FLAGS
- mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 511 * 8], eax
-
- ; Map the kernel into the higher half (second level)
- mov eax, p2_table - KERNEL_VIRTUAL_ADDR
- or eax, FLAGS
- mov dword[(p3_table_hh - KERNEL_VIRTUAL_ADDR) + 510 * 8], eax
-
- ; Map the pml4 into itself
+ ; Identity map the p4 table
mov eax, p4_table - KERNEL_VIRTUAL_ADDR
or eax, FLAGS
mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 510 * 8], eax
@@ -52,6 +42,16 @@ start:
or eax, FLAGS
mov dword [(p3_table - KERNEL_VIRTUAL_ADDR) + 0], eax
+ ; Map the kernel into the higher half
+ mov eax, p3_table_hh - KERNEL_VIRTUAL_ADDR
+ or eax, FLAGS
+ mov dword [(p4_table - KERNEL_VIRTUAL_ADDR) + 511 * 8], eax
+
+ ; Map the kernel into the higher half (second level)
+ mov eax, p2_table - KERNEL_VIRTUAL_ADDR
+ or eax, FLAGS
+ mov dword[(p3_table_hh - KERNEL_VIRTUAL_ADDR) + 510 * 8], eax
+
; Map 8MB of kernel memory (2 page directories)
mov ebx, 0
mov eax, p1_tables - KERNEL_VIRTUAL_ADDR
@@ -67,7 +67,7 @@ start:
cmp ebx, PD_LOOP_LIMIT
jne .map_pd_table
- ; Fill the page directory with the page tables
+ ; Fill the page directory with the kernel page tables
mov ecx, 0
.map_p2_table:
@@ -137,7 +137,7 @@ p3_table_hh:
p2_table:
resb 4096
p1_tables:
- resb 8192
+ resb 16384
; The stack for the kernel
diff --git a/kernel/src/asm/multiboot_header.s b/kernel/src/asm/multiboot_header.s
index b35c64ea..3bd4441c 100644
--- a/kernel/src/asm/multiboot_header.s
+++ b/kernel/src/asm/multiboot_header.s
@@ -1,25 +1,23 @@
section .multiboot_header
header_start:
align 8
- dd 0xe85250d6 ;magic_number
- dd 0 ;Protected mode
- dd header_end - header_start ;Header length
+ dd 0xe85250d6 ; Magic number
+ dd 0 ; Protected mode
+ dd header_end - header_start ; Header length
- ;compute checksum
+ ; Checksum
dd 0x100000000 - (0xe85250d6 + 0 + (header_end - header_start))
framebuffer_tag_start:
- dw 0x05 ;Type: framebuffer
- dw 0x01 ;Optional tag
- dd framebuffer_tag_end - framebuffer_tag_start ;size
- dd 0 ;Width - if 0 we let the bootloader decide
- dd 0 ;Height - same as above
- dd 0 ;Depth - same as above
+ dw 0x05 ; Tag: Framebuffer
+ dw 0x01 ; Tag is optional
+ dd framebuffer_tag_end - framebuffer_tag_start ; Size
+ dd 0 ; Width - let GRUB pick
+ dd 0 ; Height - let GRUB pick
+ dd 0 ; Depth - let GRUB pick
framebuffer_tag_end:
- ;here ends the required part of the multiboot header
- ;The following is the end tag, must be always present
- ;end tag
+ ; End Of multiboot tag
align 8
dw 0 ;type
dw 0 ;flags
diff --git a/kernel/src/common/buffer.cpp b/kernel/src/common/buffer.cpp
new file mode 100644
index 00000000..588bdd39
--- /dev/null
+++ b/kernel/src/common/buffer.cpp
@@ -0,0 +1,356 @@
+//
+// Created by 98max on 30/07/2025.
+//
+
+#include
+
+using namespace MaxOS;
+using namespace MaxOS::common;
+
+/**
+ * @brief Creates a buffer of the specified size
+ *
+ * @param size
+ */
+Buffer::Buffer(size_t size, bool update_offset)
+: m_capacity(size),
+ update_offset(update_offset)
+{
+
+ // Create the buffer
+ m_bytes = new uint8_t[size];
+
+}
+
+/**
+ * @brief Creates a buffer pointing to a source
+ *
+ * @param source The source
+ * @param size The capacity of the source
+ */
+Buffer::Buffer(void* source, size_t size, bool update_offset)
+: update_offset(update_offset)
+{
+
+ m_bytes = (uint8_t*)source;
+ m_capacity = size;
+ m_dont_delete = true;
+
+}
+
+/**
+ * @brief Destroy the buffer, freeing the memory
+ */
+Buffer::~Buffer() {
+ if(!m_dont_delete && m_bytes)
+ delete[] m_bytes;
+}
+
+/**
+ * @brief The raw pointer to the bytes stored in memory, use is not recommended
+ * @return The address of buffer's storage
+ */
+uint8_t *Buffer::raw() const{
+
+ return m_bytes;
+}
+
+/**
+ * @brief Fulls the buffer with 0's and resets the offset
+ */
+void Buffer::clear() {
+
+ m_offset = 0;
+ memset(m_bytes, 0, m_capacity);
+}
+
+/**
+ * @brief Full the buffer with a specified byte at an offset
+ *
+ * @param byte The byte to write
+ * @param offset Where to start writing (deafults to 0)
+ * @param amount
+ */
+void Buffer::full(uint8_t byte, size_t offset, size_t amount) {
+
+ // Prevent writing past the buffer bounds
+ if (amount == 0) amount = m_capacity - m_offset - offset;
+ ASSERT(m_offset + offset + amount <= capacity(), "Buffer overflow");
+
+ memset(m_bytes + m_offset + offset, byte, amount);
+
+}
+
+/**
+ * @brief The max bytes the buffer can currently store. @see Buffer:grow(size_t size) to increase this.
+ * @return The length of the buffer storage array
+ */
+size_t Buffer::capacity() const {
+ return m_capacity;
+}
+
+/**
+ * @brief Grow the buffer to fit a new size
+ *
+ * @param size The new max capacity of the buffer
+ */
+void Buffer::resize(size_t size) {
+
+ // Create the new buffer
+ auto* new_buffer = new uint8_t[size];
+
+ // Copy the old buffer
+ if(m_bytes)
+ memcpy(new_buffer, m_bytes, m_capacity);
+
+ // Store the new buffer
+ if(!m_dont_delete && m_bytes)
+ delete[] m_bytes;
+
+ m_bytes = new_buffer;
+ m_capacity = size;
+ m_dont_delete = true;
+
+}
+
+/**
+ * @brief Set the offset for where operations should begin from
+ *
+ * @param offset The new offset
+ */
+void Buffer::set_offset(size_t offset) {
+
+ if(update_offset)
+ m_offset = offset;
+
+}
+
+/**
+ * @brief Safely writes a byte to the buffer at the current offset
+ *
+ * @param byte The byte to write
+ */
+void Buffer::write(uint8_t byte) {
+ m_bytes[m_offset] = byte;
+ set_offset(m_offset + 1);
+}
+
+
+/**
+ * @brief Safely writes a byte to the buffer at the specified offset
+ *
+ * @param offset The offset into the buffer storage array
+ * @param byte The byte to write
+ */
+void Buffer::write(size_t offset, uint8_t byte) {
+
+ // Prevent writing past the buffer bounds
+ ASSERT(m_offset + offset < capacity() && offset >= 0, "Buffer overflow");
+
+ // Set the byte
+ m_bytes[m_offset + offset] = byte;
+ set_offset(m_offset + 1);
+
+}
+
+/**
+ * @brief Safely reads a byte from the buffer at the current offset
+ *
+ * @param offset The offset into the buffer storage array
+ */
+uint8_t Buffer::read() {
+ set_offset(m_offset + 1);
+ return m_bytes[m_offset - 1];
+}
+
+/**
+ * @brief Safely reads a byte from the buffer at the specified offset
+ *
+ * @param offset The offset into the buffer storage array
+ */
+uint8_t Buffer::read(size_t offset) {
+
+ // Prevent writing past the buffer bounds
+ ASSERT(m_offset + offset < capacity() && offset >= 0, "Buffer overflow");
+
+ // Set the byte
+ set_offset(m_offset + 1);
+ return m_bytes[(m_offset - 1) + offset];
+}
+
+/**
+ * @brief Copies all the bytes from another buffer into this buffer.
+ *
+ * @param buffer Where to read from
+ */
+void Buffer::copy_from(const Buffer* buffer) {
+
+ // Copy the buffer
+ ASSERT(buffer -> capacity() <= capacity(), "Copy exceeds buffer capacity");
+ copy_from(buffer -> raw(), buffer -> capacity() );
+
+}
+
+/**
+ * @brief Copies a range of bytes from another buffer into this buffer.
+ *
+ * @param buffer Where to read from
+ * @param length How much to read
+ */
+void Buffer::copy_from(const Buffer *buffer, size_t length) {
+
+ // Copy the buffer
+ ASSERT(length <= buffer -> capacity(), "Copy exceeds external buffer capacity");
+ copy_from(buffer -> raw(), length);
+
+}
+
+/**
+ * @brief Copies a range of bytes from another buffer into this buffer at a specified offset.
+ * @param source Where to read from
+ * @param length How much to read
+ * @param offset Where to start writing into this at
+ */
+void Buffer::copy_from(const Buffer *buffer, size_t length, size_t offset) {
+
+ // Copy the buffer
+ ASSERT(length <= buffer -> capacity(), "Copy exceeds external buffer capacity");
+ copy_from(buffer -> raw(), length, offset);
+
+}
+
+/**
+ * @brief Copies a range of bytes from another buffer into this buffer at a specified offset for both.
+ *
+ * @param source Where to read from
+ * @param length How much to read
+ * @param offset Where to start writing into this at
+ * @param offset Where to start reading from the other buffer
+ */
+void Buffer::copy_from(const Buffer *buffer, size_t length, size_t offset, size_t offset_other) {
+
+ // Copy the buffer
+ ASSERT(length + offset_other <= buffer -> capacity(), "Copy exceeds external buffer capacity");
+ copy_from(buffer -> raw() + offset_other, length, offset);
+
+}
+
+/**
+ * @brief Copies a range of bytes from a source into this buffer.
+ *
+ * @param source Where to read from
+ * @param length How much to read
+ */
+void Buffer::copy_from(void const *source, size_t length) {
+
+ // Copy the bytes
+ ASSERT(length + m_offset <= m_capacity, "Copy exceeds buffer capacity");
+ memcpy(m_bytes + m_offset, source, length);
+ set_offset(m_offset + length);
+}
+
+/**
+ * @brief Copies a range of bytes from a source into this buffer at a specified offset.
+ *
+ * @param source Where to read from
+ * @param length How much to read
+ * @param offset Where to start writing at
+ */
+void Buffer::copy_from(void const *source, size_t length, size_t offset) {
+
+ // Copy the bytes
+ ASSERT((length + offset + m_offset) <= m_capacity, "Copy exceeds buffer capacity");
+ memcpy(m_bytes + offset + m_offset, source, length);
+ set_offset(m_offset + length);
+
+}
+
+/**
+ * @brief Copies all the bytes from this buffer into another buffer.
+ *
+ * @param buffer Where to write to
+ */
+void Buffer::copy_to(Buffer *buffer) {
+
+ // Copy the buffer
+ ASSERT(capacity() <= buffer -> capacity(), "Copy exceeds external buffer capacity");
+ copy_to(buffer -> raw(), capacity());
+
+}
+
+/**
+ * @brief Writes a range of bytes from this buffer into another buffer.
+ *
+ * @param buffer Where to write to
+ * @param length How much to write
+ */
+void Buffer::copy_to(Buffer *buffer, size_t length) {
+
+ // Copy the buffer
+ ASSERT(length <= buffer -> capacity(), "Copy exceeds external buffer capacity");
+ copy_to(buffer -> raw(), length);
+
+}
+
+/**
+ * @brief Copies a range of bytes from this buffer into another buffer at a specified offset.
+ *
+ * @param source Where to write to
+ * @param length How much to write
+ * @param offset Where to start reading at
+ */
+void Buffer::copy_to(Buffer *buffer, size_t length, size_t offset) {
+
+ // Copy the bytes
+ ASSERT((length + offset) <= buffer -> capacity(), "Copy exceeds external buffer capacity");
+ copy_to(buffer -> raw(), length, offset);
+
+}
+
+/**
+ * @brief Copies a range of bytes from this buffer into another at an offset for each.
+ *
+ * @param destination Where to write to
+ * @param length How much to write
+ * @param offset Where to start reading from
+ * @param offset_other Where to start writing to
+ */
+void Buffer::copy_to(Buffer *buffer, size_t length, size_t offset, size_t offset_other) {
+
+ // Copy the bytes
+ ASSERT((length + offset) <= buffer -> capacity(), "Copy exceeds external buffer capacity");
+ copy_to(buffer -> raw() + offset_other, length, offset);
+
+}
+
+
+/**
+ * @brief Copies a range of bytes from this buffer into a source.
+ *
+ * @param destination Where to write to
+ * @param length How much to write
+ */
+void Buffer::copy_to(void* destination, size_t length) {
+
+ // Copy the bytes
+ ASSERT(length + m_offset <= (m_capacity), "Copy exceeds buffer capacity");
+ memcpy(destination, m_bytes + m_offset, length);
+ set_offset(m_offset + length);
+
+}
+
+/**
+ * @brief Copies a range of bytes from this buffer at an offset into a source.
+ *
+ * @param destination Where to write to
+ * @param length How much to write
+ * @param offset Where to start reading from
+ */
+void Buffer::copy_to(void *destination, size_t length, size_t offset) {
+
+ // Copy the bytes
+ ASSERT((length + offset + m_offset) <= m_capacity, "Copy exceeds buffer capacity");
+ memcpy(destination, m_bytes + offset + m_offset, length);
+ set_offset(m_offset + length);
+
+}
\ No newline at end of file
diff --git a/kernel/src/common/colour.cpp b/kernel/src/common/colour.cpp
index c9511289..765acebf 100644
--- a/kernel/src/common/colour.cpp
+++ b/kernel/src/common/colour.cpp
@@ -9,34 +9,32 @@ using namespace MaxOS::common;
Colour::Colour() = default;
Colour::Colour(uint8_t red, uint8_t green, uint8_t blue)
-: red(red),
- green(green),
- blue(blue)
-{
+ : red(red),
+ green(green),
+ blue(blue) {
}
Colour::Colour(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
-: red(red),
- green(green),
- blue(blue),
- alpha(alpha)
-{
+ : red(red),
+ green(green),
+ blue(blue),
+ alpha(alpha) {
}
Colour::~Colour() = default;
Colour::Colour(ConsoleColour colour) {
- parse_console_colour(colour);
+ parse_console_colour(colour);
}
-Colour::Colour(MaxOS::string string) {
+Colour::Colour(string string) {
- if(string[0] == '#')
- parse_hex_string(string);
- else
- parse_ansi_string(string);
+ if (string[0] == '#')
+ parse_hex_string(string);
+ else
+ parse_ansi_string(string);
}
@@ -47,19 +45,19 @@ Colour::Colour(MaxOS::string string) {
*/
void Colour::parse_hex_string(string hex_string) {
- // Check if the string is a valid hex string
- if(hex_string.length() != 7 || hex_string.length() != 9)
- return;
+ // Check if the string is a valid hex string
+ if (hex_string.length() != 7 || hex_string.length() != 9)
+ return;
- // Parse the red, green and blue values
- red = (hex_string[1] - '0') * 16 + (hex_string[2] - '0');
- green = (hex_string[3] - '0') * 16 + (hex_string[4] - '0');
- blue = (hex_string[5] - '0') * 16 + (hex_string[6] - '0');
+ // Parse the red, green and blue values
+ red = (hex_string[1] - '0') * 16 + (hex_string[2] - '0');
+ green = (hex_string[3] - '0') * 16 + (hex_string[4] - '0');
+ blue = (hex_string[5] - '0') * 16 + (hex_string[6] - '0');
- // Parse the alpha value
- alpha = 255;
- if(hex_string.length() == 9)
- alpha = (hex_string[7] - '0') * 16 + (hex_string[8] - '0');
+ // Parse the alpha value
+ alpha = 255;
+ if (hex_string.length() == 9)
+ alpha = (hex_string[7] - '0') * 16 + (hex_string[8] - '0');
}
@@ -71,52 +69,48 @@ void Colour::parse_hex_string(string hex_string) {
*/
void Colour::parse_ansi_string(string ansi_string) {
- // Check if the string is a valid ANSI string
- if(ansi_string.length() != 7 || ansi_string[0] != '\033' || ansi_string[1] != '[' || ansi_string[6] != 'm')
- return;
+ // Check if the string is a valid ANSI string
+ if (ansi_string.length() != 7 || ansi_string[0] != '\033' || ansi_string[1] != '[' || ansi_string[6] != 'm')
+ return;
- // Parse the colour
- uint8_t colour = ansi_string[5] - '0';
+ // Parse the colour
+ uint8_t colour = ansi_string[5] - '0';
+ switch (colour) {
+ case 0:
+ parse_console_colour(ConsoleColour::Black);
+ break;
- // Set the colour
- switch (colour) {
+ case 1:
+ parse_console_colour(ConsoleColour::Red);
+ break;
- case 0:
- parse_console_colour(ConsoleColour::Black);
- break;
+ case 2:
+ parse_console_colour(ConsoleColour::Green);
+ break;
- case 1:
- parse_console_colour(ConsoleColour::Red);
- break;
+ case 3:
+ parse_console_colour(ConsoleColour::Yellow);
+ break;
- case 2:
- parse_console_colour(ConsoleColour::Green);
- break;
+ case 4:
+ parse_console_colour(ConsoleColour::Blue);
+ break;
- case 3:
- parse_console_colour(ConsoleColour::Yellow);
- break;
+ case 5:
+ parse_console_colour(ConsoleColour::Magenta);
+ break;
- case 4:
- parse_console_colour(ConsoleColour::Blue);
- break;
+ case 6:
+ parse_console_colour(ConsoleColour::Cyan);
+ break;
- case 5:
- parse_console_colour(ConsoleColour::Magenta);
- break;
+ case 7:
+ parse_console_colour(ConsoleColour::White);
+ break;
- case 6:
- parse_console_colour(ConsoleColour::Cyan);
- break;
-
- case 7:
- parse_console_colour(ConsoleColour::White);
- break;
-
-
- default:
- break;
- }
+ default:
+ break;
+ }
}
/**
@@ -125,106 +119,106 @@ void Colour::parse_ansi_string(string ansi_string) {
* @param colour The console colour
*/
void Colour::parse_console_colour(ConsoleColour colour) {
- switch (colour) {
-
- case ConsoleColour::Uninitialised:
- case ConsoleColour::Black:
- red = 0;
- green = 0;
- blue = 0;
- break;
-
- case ConsoleColour::Blue:
- red = 0;
- green = 128;
- blue = 253;
- break;
-
- case ConsoleColour::Green:
- red = 0;
- green = 170;
- blue = 0;
- break;
-
- case ConsoleColour::Cyan:
- red = 0;
- green = 170;
- blue = 170;
- break;
-
- case ConsoleColour::Red:
- red = 170;
- green = 0;
- blue = 0;
- break;
-
- case ConsoleColour::Magenta:
- red = 170;
- green = 0;
- blue = 170;
- break;
-
- case ConsoleColour::Brown:
- red = 170;
- green = 85;
- blue = 0;
- break;
-
- case ConsoleColour::LightGrey:
- red = 170;
- green = 170;
- blue = 170;
- break;
-
- case ConsoleColour::DarkGrey:
- red = 85;
- green = 85;
- blue = 85;
- break;
-
- case ConsoleColour::LightBlue:
- red = 85;
- green = 85;
- blue = 255;
- break;
-
- case ConsoleColour::LightGreen:
- red = 85;
- green = 255;
- blue = 85;
- break;
-
- case ConsoleColour::LightCyan:
- red = 85;
- green = 255;
- blue = 255;
- break;
-
- case ConsoleColour::LightRed:
- red = 255;
- green = 85;
- blue = 85;
- break;
-
- case ConsoleColour::LightMagenta:
- red = 255;
- green = 85;
- blue = 255;
- break;
-
- // Same as CLION yellow
- case ConsoleColour::Yellow:
- red = 0x96;
- green = 0x82;
- blue = 0x0E;
- break;
-
- case ConsoleColour::White:
- red = 255;
- green = 255;
- blue = 255;
- break;
- }
+ switch (colour) {
+
+ case ConsoleColour::Uninitialised:
+ case ConsoleColour::Black:
+ red = 0;
+ green = 0;
+ blue = 0;
+ break;
+
+ case ConsoleColour::Blue:
+ red = 0;
+ green = 128;
+ blue = 253;
+ break;
+
+ case ConsoleColour::Green:
+ red = 0;
+ green = 170;
+ blue = 0;
+ break;
+
+ case ConsoleColour::Cyan:
+ red = 0;
+ green = 170;
+ blue = 170;
+ break;
+
+ case ConsoleColour::Red:
+ red = 170;
+ green = 0;
+ blue = 0;
+ break;
+
+ case ConsoleColour::Magenta:
+ red = 170;
+ green = 0;
+ blue = 170;
+ break;
+
+ case ConsoleColour::Brown:
+ red = 170;
+ green = 85;
+ blue = 0;
+ break;
+
+ case ConsoleColour::LightGrey:
+ red = 170;
+ green = 170;
+ blue = 170;
+ break;
+
+ case ConsoleColour::DarkGrey:
+ red = 85;
+ green = 85;
+ blue = 85;
+ break;
+
+ case ConsoleColour::LightBlue:
+ red = 85;
+ green = 85;
+ blue = 255;
+ break;
+
+ case ConsoleColour::LightGreen:
+ red = 85;
+ green = 255;
+ blue = 85;
+ break;
+
+ case ConsoleColour::LightCyan:
+ red = 85;
+ green = 255;
+ blue = 255;
+ break;
+
+ case ConsoleColour::LightRed:
+ red = 255;
+ green = 85;
+ blue = 85;
+ break;
+
+ case ConsoleColour::LightMagenta:
+ red = 255;
+ green = 85;
+ blue = 255;
+ break;
+
+ // Same as CLION yellow
+ case ConsoleColour::Yellow:
+ red = 0x96;
+ green = 0x82;
+ blue = 0x0E;
+ break;
+
+ case ConsoleColour::White:
+ red = 255;
+ green = 255;
+ blue = 255;
+ break;
+ }
}
/**
@@ -235,54 +229,54 @@ void Colour::parse_console_colour(ConsoleColour colour) {
ConsoleColour Colour::to_console_colour() const {
- if (red == 0 && green == 0 && blue == 0)
- return ConsoleColour::Black;
+ if (red == 0 && green == 0 && blue == 0)
+ return ConsoleColour::Black;
- if (red == 0 && green == 128 && blue == 253)
- return ConsoleColour::Blue;
+ if (red == 0 && green == 128 && blue == 253)
+ return ConsoleColour::Blue;
- if (red == 0 && green == 170 && blue == 0)
- return ConsoleColour::Green;
+ if (red == 0 && green == 170 && blue == 0)
+ return ConsoleColour::Green;
- if (red == 0 && green == 170 && blue == 170)
- return ConsoleColour::Cyan;
+ if (red == 0 && green == 170 && blue == 170)
+ return ConsoleColour::Cyan;
- if (red == 170 && green == 0 && blue == 0)
- return ConsoleColour::Red;
+ if (red == 170 && green == 0 && blue == 0)
+ return ConsoleColour::Red;
- if (red == 170 && green == 0 && blue == 170)
- return ConsoleColour::Magenta;
+ if (red == 170 && green == 0 && blue == 170)
+ return ConsoleColour::Magenta;
- if (red == 170 && green == 85 && blue == 0)
- return ConsoleColour::Brown;
+ if (red == 170 && green == 85 && blue == 0)
+ return ConsoleColour::Brown;
- if (red == 170 && green == 170 && blue == 170)
- return ConsoleColour::LightGrey;
+ if (red == 170 && green == 170 && blue == 170)
+ return ConsoleColour::LightGrey;
- if (red == 85 && green == 85 && blue == 85)
- return ConsoleColour::DarkGrey;
+ if (red == 85 && green == 85 && blue == 85)
+ return ConsoleColour::DarkGrey;
- if (red == 85 && green == 85 && blue == 255)
- return ConsoleColour::LightBlue;
+ if (red == 85 && green == 85 && blue == 255)
+ return ConsoleColour::LightBlue;
- if (red == 85 && green == 255 && blue == 85)
- return ConsoleColour::LightGreen;
+ if (red == 85 && green == 255 && blue == 85)
+ return ConsoleColour::LightGreen;
- if (red == 85 && green == 255 && blue == 255)
- return ConsoleColour::LightCyan;
+ if (red == 85 && green == 255 && blue == 255)
+ return ConsoleColour::LightCyan;
- if (red == 255 && green == 85 && blue == 85)
- return ConsoleColour::LightRed;
+ if (red == 255 && green == 85 && blue == 85)
+ return ConsoleColour::LightRed;
- if (red == 255 && green == 85 && blue == 255)
- return ConsoleColour::LightMagenta;
+ if (red == 255 && green == 85 && blue == 255)
+ return ConsoleColour::LightMagenta;
- if (red == 0x96 && green == 0x82 && blue == 0x0E)
- return ConsoleColour::Yellow;
+ if (red == 0x96 && green == 0x82 && blue == 0x0E)
+ return ConsoleColour::Yellow;
- if (red == 255 && green == 255 && blue == 255)
- return ConsoleColour::White;
+ if (red == 255 && green == 255 && blue == 255)
+ return ConsoleColour::White;
- // Return a default value in case no match is found
- return ConsoleColour::Black;
+ // Return a default value in case no match is found
+ return ConsoleColour::Black;
}
diff --git a/kernel/src/common/graphicsContext.cpp b/kernel/src/common/graphicsContext.cpp
index 9febe0b8..8946199d 100644
--- a/kernel/src/common/graphicsContext.cpp
+++ b/kernel/src/common/graphicsContext.cpp
@@ -6,84 +6,83 @@
using namespace MaxOS::common;
-GraphicsContext::GraphicsContext()
-{
-
-
- // VirtualBox VGA palette
- m_colour_pallet[0x00] = Colour(0x00,0x00,0x00); // Black
- m_colour_pallet[0x01] = Colour(0x00,0x00,0xA8); // Duke Blue
- m_colour_pallet[0x02] = Colour(0x00,0xA8,0x00); // Islamic Green
- m_colour_pallet[0x03] = Colour(0x00,0xA8,0xA8); // Persian Green
- m_colour_pallet[0x04] = Colour(0xA8,0x00,0x00); // Dark Candy Apple Red
- m_colour_pallet[0x05] = Colour(0xA8,0x00,0xA8); // Heliotrope Magenta
-
- m_colour_pallet[0x06] = Colour(0xA8,0xA8,0x00); // Light Gold
- m_colour_pallet[0x07] = Colour(0xA8,0xA8,0xA8); // Dark Gray (X11)
- m_colour_pallet[0x08] = Colour(0x00,0x00,0x57); // Cetacean Blue
- m_colour_pallet[0x09] = Colour(0x00,0x00,0xFF); // Blue
- m_colour_pallet[0x0A] = Colour(0x00,0xA8,0x57); // Green (Pigment)
- m_colour_pallet[0x0B] = Colour(0x00,0xA8,0xFF); // Vivid Cerulean
- m_colour_pallet[0x0C] = Colour(0xA8,0x00,0x57); // Jazz berry Jam
- m_colour_pallet[0x0D] = Colour(0xA8,0x00,0x57); // Jazz berry Jam
- m_colour_pallet[0x0E] = Colour(0xA8,0xA8,0x57); // Olive Green
- m_colour_pallet[0x0F] = Colour(0xA8,0xA8,0xFF); // Maximum Blue Purple
-
- m_colour_pallet[0x10] = Colour(0x00,0x57,0x00); // Dark Green (X11)
- m_colour_pallet[0x11] = Colour(0x00,0x57,0xA8); // Cobalt Blue
- m_colour_pallet[0x12] = Colour(0x00,0xFF,0x00); // Electric Green
- m_colour_pallet[0x13] = Colour(0x00,0xFF,0xA8); // Medium Spring Green
- m_colour_pallet[0x14] = Colour(0xA8,0x57,0x00); // Windsor Tan
- m_colour_pallet[0x15] = Colour(0xA8,0x57,0xA8); // Purpureus
- m_colour_pallet[0x16] = Colour(0xA8,0xFF,0x00); // Spring Bud
- m_colour_pallet[0x17] = Colour(0xA8,0xFF,0xA8); // Mint Green
- m_colour_pallet[0x18] = Colour(0x00,0x57,0x57); // Midnight Green (Eagle Green)
- m_colour_pallet[0x19] = Colour(0x00,0x57,0xFF); // Blue (RYB)
- m_colour_pallet[0x1A] = Colour(0x00,0xFF,0x57); // Malachite
- m_colour_pallet[0x1B] = Colour(0x00,0xFF,0xFF); // Aqua
- m_colour_pallet[0x1C] = Colour(0xA8,0x57,0x57); // Middle Red Purple
- m_colour_pallet[0x1D] = Colour(0xA8,0x57,0xFF); // Lavender Indigo
- m_colour_pallet[0x1E] = Colour(0xA8,0xFF,0x57); // Olive Green
- m_colour_pallet[0x1F] = Colour(0xA8,0xFF,0xFF); // Celeste
-
- m_colour_pallet[0x20] = Colour(0x57,0x00,0x00); // Blood Red
- m_colour_pallet[0x21] = Colour(0x57,0x00,0xA8); // Metallic Violet
- m_colour_pallet[0x22] = Colour(0x57,0xA8,0x00); // Kelly Green
- m_colour_pallet[0x23] = Colour(0x57,0xA8,0xA8); // Cadet Blue
- m_colour_pallet[0x24] = Colour(0xFF,0x00,0x00); // Red
- m_colour_pallet[0x25] = Colour(0xFF,0x00,0xA8); // Fashion Fuchsia
- m_colour_pallet[0x26] = Colour(0xFF,0xA8,0x00); // Chrome Yellow
- m_colour_pallet[0x27] = Colour(0xFF,0xA8,0xA8); // Light Salmon Pink
- m_colour_pallet[0x28] = Colour(0x57,0x00,0x57); // Imperial Purple
- m_colour_pallet[0x29] = Colour(0x57,0x00,0xFF); // Electric Indigo
- m_colour_pallet[0x2A] = Colour(0x57,0xA8,0x57); // Apple
- m_colour_pallet[0x2B] = Colour(0x57,0xA8,0xFF); // Blue Jeans
- m_colour_pallet[0x2C] = Colour(0xFF,0x00,0x57); // Folly
- m_colour_pallet[0x2D] = Colour(0xFF,0x00,0xFF); // Fuchsia
- m_colour_pallet[0x2E] = Colour(0xFF,0xA8,0x57); // Rajah
- m_colour_pallet[0x2F] = Colour(0xFF,0xA8,0xFF); // Rich Brilliant Lavender
-
- m_colour_pallet[0x30] = Colour(0x57,0x57,0x00); // Dark Bronze (Coin)
- m_colour_pallet[0x31] = Colour(0x57,0x57,0xA8); // Liberty
- m_colour_pallet[0x32] = Colour(0x57,0xFF,0x00); // Chlorophyll Green
- m_colour_pallet[0x33] = Colour(0x57,0xFF,0xA8); // Medium Aquamarine
- m_colour_pallet[0x34] = Colour(0xFF,0x57,0x00); // Orange (Pantone)
- m_colour_pallet[0x35] = Colour(0xFF,0x57,0xA8); // Brilliant Rose
- m_colour_pallet[0x36] = Colour(0xFF,0xFF,0x00); // Yellow
- m_colour_pallet[0x37] = Colour(0xFF,0xFF,0xA8); // Calamansi
- m_colour_pallet[0x38] = Colour(0x57,0x57,0x57); // Davy's Grey
- m_colour_pallet[0x39] = Colour(0x57,0x57,0xFF); // Very Light Blue
- m_colour_pallet[0x3A] = Colour(0x57,0xFF,0x57); // Screamin' Green
- m_colour_pallet[0x3B] = Colour(0x57,0xFF,0xFF); // Electric Blue
- m_colour_pallet[0x3C] = Colour(0xFF,0x57,0x57); // Sunset Orange
- m_colour_pallet[0x3D] = Colour(0xFF,0x57,0xFF); // Shocking Pink (Crayola)
- m_colour_pallet[0x3E] = Colour(0xFF,0xFF,0x57); // Shocking Pink (Crayola)
- m_colour_pallet[0x3F] = Colour(0xFF,0xFF,0xFF); // White
-
-
- // Set the rest of the palette to black
- for(uint8_t color_code = 255; color_code >= 0x40; --color_code)
- m_colour_pallet[color_code] = Colour(0,0,0);
+GraphicsContext::GraphicsContext() {
+
+
+ // VirtualBox VGA palette
+ m_colour_pallet[0x00] = Colour(0x00, 0x00, 0x00); // Black
+ m_colour_pallet[0x01] = Colour(0x00, 0x00, 0xA8); // Duke Blue
+ m_colour_pallet[0x02] = Colour(0x00, 0xA8, 0x00); // Islamic Green
+ m_colour_pallet[0x03] = Colour(0x00, 0xA8, 0xA8); // Persian Green
+ m_colour_pallet[0x04] = Colour(0xA8, 0x00, 0x00); // Dark Candy Apple Red
+ m_colour_pallet[0x05] = Colour(0xA8, 0x00, 0xA8); // Heliotrope Magenta
+
+ m_colour_pallet[0x06] = Colour(0xA8, 0xA8, 0x00); // Light Gold
+ m_colour_pallet[0x07] = Colour(0xA8, 0xA8, 0xA8); // Dark Gray (X11)
+ m_colour_pallet[0x08] = Colour(0x00, 0x00, 0x57); // Cetacean Blue
+ m_colour_pallet[0x09] = Colour(0x00, 0x00, 0xFF); // Blue
+ m_colour_pallet[0x0A] = Colour(0x00, 0xA8, 0x57); // Green (Pigment)
+ m_colour_pallet[0x0B] = Colour(0x00, 0xA8, 0xFF); // Vivid Cerulean
+ m_colour_pallet[0x0C] = Colour(0xA8, 0x00, 0x57); // Jazz berry Jam
+ m_colour_pallet[0x0D] = Colour(0xA8, 0x00, 0x57); // Jazz berry Jam
+ m_colour_pallet[0x0E] = Colour(0xA8, 0xA8, 0x57); // Olive Green
+ m_colour_pallet[0x0F] = Colour(0xA8, 0xA8, 0xFF); // Maximum Blue Purple
+
+ m_colour_pallet[0x10] = Colour(0x00, 0x57, 0x00); // Dark Green (X11)
+ m_colour_pallet[0x11] = Colour(0x00, 0x57, 0xA8); // Cobalt Blue
+ m_colour_pallet[0x12] = Colour(0x00, 0xFF, 0x00); // Electric Green
+ m_colour_pallet[0x13] = Colour(0x00, 0xFF, 0xA8); // Medium Spring Green
+ m_colour_pallet[0x14] = Colour(0xA8, 0x57, 0x00); // Windsor Tan
+ m_colour_pallet[0x15] = Colour(0xA8, 0x57, 0xA8); // Purpureus
+ m_colour_pallet[0x16] = Colour(0xA8, 0xFF, 0x00); // Spring Bud
+ m_colour_pallet[0x17] = Colour(0xA8, 0xFF, 0xA8); // Mint Green
+ m_colour_pallet[0x18] = Colour(0x00, 0x57, 0x57); // Midnight Green (Eagle Green)
+ m_colour_pallet[0x19] = Colour(0x00, 0x57, 0xFF); // Blue (RYB)
+ m_colour_pallet[0x1A] = Colour(0x00, 0xFF, 0x57); // Malachite
+ m_colour_pallet[0x1B] = Colour(0x00, 0xFF, 0xFF); // Aqua
+ m_colour_pallet[0x1C] = Colour(0xA8, 0x57, 0x57); // Middle Red Purple
+ m_colour_pallet[0x1D] = Colour(0xA8, 0x57, 0xFF); // Lavender Indigo
+ m_colour_pallet[0x1E] = Colour(0xA8, 0xFF, 0x57); // Olive Green
+ m_colour_pallet[0x1F] = Colour(0xA8, 0xFF, 0xFF); // Celeste
+
+ m_colour_pallet[0x20] = Colour(0x57, 0x00, 0x00); // Blood Red
+ m_colour_pallet[0x21] = Colour(0x57, 0x00, 0xA8); // Metallic Violet
+ m_colour_pallet[0x22] = Colour(0x57, 0xA8, 0x00); // Kelly Green
+ m_colour_pallet[0x23] = Colour(0x57, 0xA8, 0xA8); // Cadet Blue
+ m_colour_pallet[0x24] = Colour(0xFF, 0x00, 0x00); // Red
+ m_colour_pallet[0x25] = Colour(0xFF, 0x00, 0xA8); // Fashion Fuchsia
+ m_colour_pallet[0x26] = Colour(0xFF, 0xA8, 0x00); // Chrome Yellow
+ m_colour_pallet[0x27] = Colour(0xFF, 0xA8, 0xA8); // Light Salmon Pink
+ m_colour_pallet[0x28] = Colour(0x57, 0x00, 0x57); // Imperial Purple
+ m_colour_pallet[0x29] = Colour(0x57, 0x00, 0xFF); // Electric Indigo
+ m_colour_pallet[0x2A] = Colour(0x57, 0xA8, 0x57); // Apple
+ m_colour_pallet[0x2B] = Colour(0x57, 0xA8, 0xFF); // Blue Jeans
+ m_colour_pallet[0x2C] = Colour(0xFF, 0x00, 0x57); // Folly
+ m_colour_pallet[0x2D] = Colour(0xFF, 0x00, 0xFF); // Fuchsia
+ m_colour_pallet[0x2E] = Colour(0xFF, 0xA8, 0x57); // Rajah
+ m_colour_pallet[0x2F] = Colour(0xFF, 0xA8, 0xFF); // Rich Brilliant Lavender
+
+ m_colour_pallet[0x30] = Colour(0x57, 0x57, 0x00); // Dark Bronze (Coin)
+ m_colour_pallet[0x31] = Colour(0x57, 0x57, 0xA8); // Liberty
+ m_colour_pallet[0x32] = Colour(0x57, 0xFF, 0x00); // Chlorophyll Green
+ m_colour_pallet[0x33] = Colour(0x57, 0xFF, 0xA8); // Medium Aquamarine
+ m_colour_pallet[0x34] = Colour(0xFF, 0x57, 0x00); // Orange (Pantone)
+ m_colour_pallet[0x35] = Colour(0xFF, 0x57, 0xA8); // Brilliant Rose
+ m_colour_pallet[0x36] = Colour(0xFF, 0xFF, 0x00); // Yellow
+ m_colour_pallet[0x37] = Colour(0xFF, 0xFF, 0xA8); // Calamansi
+ m_colour_pallet[0x38] = Colour(0x57, 0x57, 0x57); // Davy's Grey
+ m_colour_pallet[0x39] = Colour(0x57, 0x57, 0xFF); // Very Light Blue
+ m_colour_pallet[0x3A] = Colour(0x57, 0xFF, 0x57); // Screamin' Green
+ m_colour_pallet[0x3B] = Colour(0x57, 0xFF, 0xFF); // Electric Blue
+ m_colour_pallet[0x3C] = Colour(0xFF, 0x57, 0x57); // Sunset Orange
+ m_colour_pallet[0x3D] = Colour(0xFF, 0x57, 0xFF); // Shocking Pink (Crayola)
+ m_colour_pallet[0x3E] = Colour(0xFF, 0xFF, 0x57); // Shocking Pink (Crayola)
+ m_colour_pallet[0x3F] = Colour(0xFF, 0xFF, 0xFF); // White
+
+
+ // Set the rest of the palette to black
+ for (uint8_t color_code = 255; color_code >= 0x40; --color_code)
+ m_colour_pallet[color_code] = Colour(0, 0, 0);
}
@@ -99,21 +98,21 @@ GraphicsContext::~GraphicsContext() = default;
*/
void GraphicsContext::render_pixel(uint32_t x, uint32_t y, uint32_t colour) {
- // Call the correct put_pixel function based on the color depth
- switch (m_color_depth) {
- case 8:
- render_pixel_8_bit(x, y, colour);
- break;
- case 16:
- render_pixel_16_bit(x, y, colour);
- break;
- case 24:
- render_pixel_24_bit(x, y, colour);
- break;
- case 32:
- render_pixel_32_bit(x, y, colour);
- break;
- }
+ // Call the correct put_pixel function based on the color depth
+ switch (m_color_depth) {
+ case 8:
+ render_pixel_8_bit(x, y, colour);
+ break;
+ case 16:
+ render_pixel_16_bit(x, y, colour);
+ break;
+ case 24:
+ render_pixel_24_bit(x, y, colour);
+ break;
+ case 32:
+ render_pixel_32_bit(x, y, colour);
+ break;
+ }
}
@@ -170,19 +169,19 @@ void GraphicsContext::render_pixel_32_bit(uint32_t, uint32_t, uint32_t) {
* @return The colour of the pixel or white if the pixel is not supported
*/
uint32_t GraphicsContext::get_rendered_pixel(uint32_t x, uint32_t y) {
- // Call the correct get_pixel function based on the color depth
- switch (m_color_depth) {
- case 8:
- return get_rendered_pixel_8_bit(x, y);
- case 16:
- return get_rendered_pixel_16_bit(x, y);
- case 24:
- return get_rendered_pixel_24_bit(x, y);
- case 32:
- return get_rendered_pixel_32_bit(x, y);
- }
-
- return colour_to_int(Colour(0xFF, 0xFF, 0xFF));
+ // Call the correct get_pixel function based on the color depth
+ switch (m_color_depth) {
+ case 8:
+ return get_rendered_pixel_8_bit(x, y);
+ case 16:
+ return get_rendered_pixel_16_bit(x, y);
+ case 24:
+ return get_rendered_pixel_24_bit(x, y);
+ case 32:
+ return get_rendered_pixel_32_bit(x, y);
+ }
+
+ return colour_to_int(Colour(0xFF, 0xFF, 0xFF));
}
/**
@@ -193,7 +192,7 @@ uint32_t GraphicsContext::get_rendered_pixel(uint32_t x, uint32_t y) {
* @return The 8Bit colour of the pixel
*/
uint8_t GraphicsContext::get_rendered_pixel_8_bit(uint32_t, uint32_t) {
- return 0;
+ return 0;
}
/**
@@ -204,7 +203,7 @@ uint8_t GraphicsContext::get_rendered_pixel_8_bit(uint32_t, uint32_t) {
* @return The 16Bit colour of the pixel
*/
uint16_t GraphicsContext::get_rendered_pixel_16_bit(uint32_t, uint32_t) {
- return 0;
+ return 0;
}
/**
@@ -215,7 +214,7 @@ uint16_t GraphicsContext::get_rendered_pixel_16_bit(uint32_t, uint32_t) {
* @return The 24Bit colour of the pixel
*/
uint32_t GraphicsContext::get_rendered_pixel_24_bit(uint32_t, uint32_t) {
- return 0;
+ return 0;
}
/**
@@ -226,7 +225,7 @@ uint32_t GraphicsContext::get_rendered_pixel_24_bit(uint32_t, uint32_t) {
* @return The 32Bit colour of the pixel
*/
uint32_t GraphicsContext::get_rendered_pixel_32_bit(uint32_t, uint32_t) {
- return 0;
+ return 0;
}
/**
@@ -235,56 +234,49 @@ uint32_t GraphicsContext::get_rendered_pixel_32_bit(uint32_t, uint32_t) {
* @param colour The colour class to convert
* @return The integer value of the colour
*/
-uint32_t GraphicsContext::colour_to_int(const Colour& colour) {
-
- switch(m_color_depth)
- {
- case 8:
- {
- uint32_t result = 0;
- int mindistance = 0xfffffff;
- for(uint32_t i = 0; i <= 255; ++i)
- {
- Colour* c = &m_colour_pallet[i];
- int distance =
- ((int)colour.red-(int)c->red)*((int)colour.red-(int)c->red)
- +((int)colour.green-(int)c->green)*((int)colour.green-(int)c->green)
- +((int)colour.blue-(int)c->blue)*((int)colour.blue-(int)c->blue);
- if(distance < mindistance)
- {
- mindistance = distance;
- result = i;
- }
- }
- return result;
- }
- case 16:
- {
- // 16-Bit colours RRRRRGGGGGGBBBBB
- return ((uint16_t)(colour.red & 0xF8)) << 8
- | ((uint16_t)(colour.green & 0xFC)) << 3
- | ((uint16_t)(colour.blue & 0xF8) >> 3);
- }
- case 24:
- {
- return (uint32_t)colour.red << 16
- | (uint32_t)colour.green << 8
- | (uint32_t)colour.blue;
- }
- default:
- case 32:
- {
- uint32_t red_hex = ((uint32_t)colour.red & 0xFF) << 16;
- uint32_t green_hex = ((uint32_t)colour.green & 0xFF) << 8;
- uint32_t blue_hex = (uint32_t)colour.blue & 0xFF;
- uint32_t alpha_hex = ((uint32_t)colour.alpha & 0xFF) << 24;
-
- uint32_t hexValue = red_hex | green_hex | blue_hex | alpha_hex;
-
-
- return hexValue;
- }
- }
+uint32_t GraphicsContext::colour_to_int(const Colour &colour) {
+
+ switch (m_color_depth) {
+ case 8: {
+ uint32_t result = 0;
+ int mindistance = 0xfffffff;
+ for (uint32_t i = 0; i <= 255; ++i) {
+ Colour *c = &m_colour_pallet[i];
+ int distance =
+ ((int) colour.red - (int) c->red) * ((int) colour.red - (int) c->red)
+ + ((int) colour.green - (int) c->green) * ((int) colour.green - (int) c->green)
+ + ((int) colour.blue - (int) c->blue) * ((int) colour.blue - (int) c->blue);
+ if (distance < mindistance) {
+ mindistance = distance;
+ result = i;
+ }
+ }
+ return result;
+ }
+ case 16: {
+ // 16-Bit colours RRRRRGGGGGGBBBBB
+ return ((uint16_t) (colour.red & 0xF8)) << 8
+ | ((uint16_t) (colour.green & 0xFC)) << 3
+ | ((uint16_t) (colour.blue & 0xF8) >> 3);
+ }
+ case 24: {
+ return (uint32_t) colour.red << 16
+ | (uint32_t) colour.green << 8
+ | (uint32_t) colour.blue;
+ }
+ default:
+ case 32: {
+ uint32_t red_hex = ((uint32_t) colour.red & 0xFF) << 16;
+ uint32_t green_hex = ((uint32_t) colour.green & 0xFF) << 8;
+ uint32_t blue_hex = (uint32_t) colour.blue & 0xFF;
+ uint32_t alpha_hex = ((uint32_t) colour.alpha & 0xFF) << 24;
+
+ uint32_t hexValue = red_hex | green_hex | blue_hex | alpha_hex;
+
+
+ return hexValue;
+ }
+ }
}
/**
@@ -294,53 +286,49 @@ uint32_t GraphicsContext::colour_to_int(const Colour& colour) {
* @return The colour class of the integer value
*/
Colour GraphicsContext::int_to_colour(uint32_t colour) {
- switch (m_color_depth) {
+ switch (m_color_depth) {
- case 8:
- {
- // Return the colour from the palette
- return m_colour_pallet[colour & 0xFF];
- }
+ case 8: {
+ // Return the colour from the palette
+ return m_colour_pallet[colour & 0xFF];
+ }
- case 16:
- {
- // 16-Bit Colour: 5 bits for red, 6 bits for green, 5 bits for blue (RRRRR,GGGGGG,BBBBB)
- Colour result;
+ case 16: {
+ // 16-Bit Colour: 5 bits for red, 6 bits for green, 5 bits for blue (RRRRR,GGGGGG,BBBBB)
+ Colour result;
- result.red = (colour & 0xF800) >> 8;
- result.green = (colour & 0x07E0) >> 3;
- result.blue = (colour & 0x001F) << 3;
+ result.red = (colour & 0xF800) >> 8;
+ result.green = (colour & 0x07E0) >> 3;
+ result.blue = (colour & 0x001F) << 3;
- return result;
- }
+ return result;
+ }
- case 24:
- {
- // 24-Bit Colour: 8 bits for red, 8 bits for green, 8 bits for blue (RRRRRRRR,GGGGGGGG,BBBBBBBB)
- Colour result;
+ case 24: {
+ // 24-Bit Colour: 8 bits for red, 8 bits for green, 8 bits for blue (RRRRRRRR,GGGGGGGG,BBBBBBBB)
+ Colour result;
- result.red = (colour & 0xFF0000) >> 16;
- result.green = (colour & 0x00FF00) >> 8;
- result.blue = (colour & 0x0000FF);
+ result.red = (colour & 0xFF0000) >> 16;
+ result.green = (colour & 0x00FF00) >> 8;
+ result.blue = (colour & 0x0000FF);
- return result;
- }
+ return result;
+ }
- default:
- case 32:
- {
- Colour result;
+ default:
+ case 32: {
+ Colour result;
- uint32_t hex_value = colour;
- result.red = (hex_value >> 16) & 0xFF;
- result.green = (hex_value >> 8) & 0xFF;
- result.blue = hex_value & 0xFF;
- result.alpha = (hex_value >> 24) & 0xFF;
+ uint32_t hex_value = colour;
+ result.red = (hex_value >> 16) & 0xFF;
+ result.green = (hex_value >> 8) & 0xFF;
+ result.blue = hex_value & 0xFF;
+ result.alpha = (hex_value >> 24) & 0xFF;
- return result;
+ return result;
- }
- }
+ }
+ }
}
/**
@@ -349,7 +337,7 @@ Colour GraphicsContext::int_to_colour(uint32_t colour) {
* @return The width of the screen
*/
uint32_t GraphicsContext::width() const {
- return m_width;
+ return m_width;
}
/**
@@ -358,7 +346,7 @@ uint32_t GraphicsContext::width() const {
* @return The height of the screen
*/
uint32_t GraphicsContext::height() const {
- return m_height;
+ return m_height;
}
/**
@@ -366,7 +354,7 @@ uint32_t GraphicsContext::height() const {
* @return The color depth
*/
uint32_t GraphicsContext::color_depth() const {
- return m_color_depth;
+ return m_color_depth;
}
/**
@@ -376,10 +364,10 @@ uint32_t GraphicsContext::color_depth() const {
* @param y The y coordinate of the pixel
* @param colour The colour of the pixel
*/
-void GraphicsContext::put_pixel(int32_t x, int32_t y, const Colour& colour) {
+void GraphicsContext::put_pixel(int32_t x, int32_t y, const Colour &colour) {
- // Convert the colour to an integer and then print it
- putPixel(x,y, colour_to_int(colour));
+ // Convert the colour to an integer and then print it
+ putPixel(x, y, colour_to_int(colour));
}
/**
@@ -391,17 +379,17 @@ void GraphicsContext::put_pixel(int32_t x, int32_t y, const Colour& colour) {
*/
void GraphicsContext::putPixel(int32_t x, int32_t y, uint32_t colour) {
- if (0 > x || (uint32_t)x >= m_width) {
- return;
- }
+ if (0 > x || (uint32_t) x >= m_width) {
+ return;
+ }
- // Check if the pixel is within the m_height of the screen
- if (0 > y || (uint32_t) y >= m_height) {
- return;
- }
+ // Check if the pixel is within the m_height of the screen
+ if (0 > y || (uint32_t) y >= m_height) {
+ return;
+ }
- // Render the pixel
- render_pixel(x, mirror_y_axis ? m_height - y - 1 : y, colour);
+ // Render the pixel
+ render_pixel(x, mirror_y_axis ? m_height - y - 1 : y, colour);
}
@@ -414,21 +402,13 @@ void GraphicsContext::putPixel(int32_t x, int32_t y, uint32_t colour) {
*/
Colour GraphicsContext::get_pixel(int32_t x, int32_t y) {
- // Check if the pixel is within the m_width of the screen
- if (0 > x || (uint32_t)x >= m_width) {
- return {0,0,0};
- }
-
- // Check if the pixel is within the m_height of the screen
- if (0 > y || (uint32_t) y >= m_height) {
- return {0,0,0};
- }
-
- // Get the pixel and convert it to a colour
- uint32_t translated_color = get_rendered_pixel(x, mirror_y_axis ? m_height - y - 1 : y);
- return int_to_colour(translated_color);
-
+ // Check if the pixel is within the bounds of the screen
+ if (0 > x || (uint32_t) x >= m_width || 0 > y || (uint32_t) y >= m_height)
+ return {0, 0, 0};
+ // Get the pixel and convert it to a colour
+ uint32_t translated_color = get_rendered_pixel(x, mirror_y_axis ? m_height - y - 1 : y);
+ return int_to_colour(translated_color);
}
/**
@@ -438,16 +418,17 @@ Colour GraphicsContext::get_pixel(int32_t x, int32_t y) {
* @param y The y coordinate of the pixel
*/
void GraphicsContext::invert_pixel(int32_t x, int32_t y) {
- // Get the pixel
- Colour colour = get_pixel(x, y);
- // Invert the pixel
- colour.red = 255 - colour.red;
- colour.green = 255 - colour.green;
- colour.blue = 255 - colour.blue;
+ // Get the pixel
+ Colour colour = get_pixel(x, y);
+
+ // Invert the pixel
+ colour.red = 255 - colour.red;
+ colour.green = 255 - colour.green;
+ colour.blue = 255 - colour.blue;
- // Render the pixel
- put_pixel(x, y, colour);
+ // Render the pixel
+ put_pixel(x, y, colour);
}
@@ -460,8 +441,8 @@ void GraphicsContext::invert_pixel(int32_t x, int32_t y) {
* @param y1 The y coordinate of the final point
* @param colour The colour of the line
*/
-void GraphicsContext::draw_line(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const Colour& colour) {
- drawLine(x0,y0,x1,y1, colour_to_int(colour));
+void GraphicsContext::draw_line(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const Colour &colour) {
+ drawLine(x0, y0, x1, y1, colour_to_int(colour));
}
/**
@@ -475,87 +456,82 @@ void GraphicsContext::draw_line(int32_t x0, int32_t y0, int32_t x1, int32_t y1,
*/
void GraphicsContext::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t colour) {
- // Store the minimum and maximum y values
- bool y_0_is_smaller = y0 < y1;
- int32_t y_min = y_0_is_smaller ? y0 : y1;
- int32_t y_max = y_0_is_smaller ? y1 : y0;
-
- //Reverse the points to draw from left to right
- if(x1 < x0){
- drawLine(x1,y1,x0,y0,colour);
- return;
- }
-
- // Vertical line
- if(x1 == x0)
- {
- // Force the line to be within the screen
- if(y_min < 0) y_min = 0;
- if(y_max >= m_height)
- y_max = m_height - 1;
-
- // Mirror the Y axis as directly calling put_pixel will not do this
- if(mirror_y_axis)
- {
- int32_t temp = y_max;
- y_max = m_height - y_min - 1;
- y_min = m_height - temp - 1;
- }
-
- // Check that the line is within the screen
- if (0 > x0 || (uint32_t) x0 >= m_width) {
- return;
- }
-
- // Draw the line
- for(int32_t y = y_min; y <= y_max; ++y)
- putPixel(x0, y, colour);
-
- return;
- }
-
- // Horizontal line
- if(y1 == y0)
- {
- // Ensure the line is within the screen
- if(x0 < 0) x0 = 0;
- if(x1 >= m_width) x1 = m_width -1;
-
- // Mirror the Y axis as directly calling put_pixel will not do this
- if(mirror_y_axis)
- y0 = m_height -y0-1;
-
- // Check that the line is within the screen
- if (0 > y0 || y0 >= m_height)
- return;
-
- // Draw the line
- for(int32_t x = x0; x <= x1; ++x)
- putPixel(x,y0,colour);
- }
-
- // If the line is not horizontal or vertical then it must be a diagonal line
- // Find the slope of the line
- float slope = ((float)(y1-y0))/(x1-x0);
-
- // A slope that is more horizontal should be drawn by incrementing x
- if(-1 <= slope && slope <= 1)
- {
- float y = y0;
- for(int32_t x = x0; x <= x1; x++, y+=slope)
- putPixel(x, (int32_t)y, colour);
- }
-
- // A slope that is more vertical should be drawn by incrementing y
- else
- {
- // Invert the slope
- slope = 1.0f/slope;
-
- float x = x0;
- for(int32_t y = y_min; y <= y_max; x+=slope, y++)
- putPixel((int32_t)x, y, colour);
- }
+ // Store the minimum and maximum y values
+ bool y_0_is_smaller = y0 < y1;
+ int32_t y_min = y_0_is_smaller ? y0 : y1;
+ int32_t y_max = y_0_is_smaller ? y1 : y0;
+
+ //Reverse the points to draw from left to right
+ if (x1 < x0) {
+ drawLine(x1, y1, x0, y0, colour);
+ return;
+ }
+
+ // Vertical line
+ if (x1 == x0) {
+ // Force the line to be within the screen
+ if (y_min < 0) y_min = 0;
+ if (y_max >= m_height)
+ y_max = m_height - 1;
+
+ // Mirror the Y axis as directly calling put_pixel will not do this
+ if (mirror_y_axis) {
+ int32_t temp = y_max;
+ y_max = m_height - y_min - 1;
+ y_min = m_height - temp - 1;
+ }
+
+ // Check that the line is within the screen
+ if (0 > x0 || (uint32_t) x0 >= m_width) {
+ return;
+ }
+
+ // Draw the line
+ for (int32_t y = y_min; y <= y_max; ++y)
+ putPixel(x0, y, colour);
+
+ return;
+ }
+
+ // Horizontal line
+ if (y1 == y0) {
+ // Ensure the line is within the screen
+ if (x0 < 0) x0 = 0;
+ if (x1 >= m_width) x1 = m_width - 1;
+
+ // Mirror the Y axis as directly calling put_pixel will not do this
+ if (mirror_y_axis)
+ y0 = m_height - y0 - 1;
+
+ // Check that the line is within the screen
+ if (0 > y0 || y0 >= m_height)
+ return;
+
+ // Draw the line
+ for (int32_t x = x0; x <= x1; ++x)
+ putPixel(x, y0, colour);
+ }
+
+ // If the line is not horizontal or vertical then it must be a diagonal line
+ // Find the slope of the line
+ float slope = ((float) (y1 - y0)) / (x1 - x0);
+
+ // A slope that is more horizontal should be drawn by incrementing x
+ if (-1 <= slope && slope <= 1) {
+ float y = y0;
+ for (int32_t x = x0; x <= x1; x++, y += slope)
+ putPixel(x, (int32_t) y, colour);
+ }
+
+ // A slope that is more vertical should be drawn by incrementing y
+ else {
+ // Invert the slope
+ slope = 1.0f / slope;
+
+ float x = x0;
+ for (int32_t y = y_min; y <= y_max; x += slope, y++)
+ putPixel((int32_t) x, y, colour);
+ }
}
/**
@@ -567,8 +543,8 @@ void GraphicsContext::drawLine(int32_t x0, int32_t y0, int32_t x1, int32_t y1, u
* @param y1 The y coordinate of the bottom right corner
* @param colour The colour of the rectangle
*/
-void GraphicsContext::draw_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const Colour& colour) {
- draw_rectangle(x0, y0, x1, y1, colour_to_int(colour));
+void GraphicsContext::draw_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const Colour &colour) {
+ draw_rectangle(x0, y0, x1, y1, colour_to_int(colour));
}
@@ -583,15 +559,15 @@ void GraphicsContext::draw_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t
*/
void GraphicsContext::draw_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t colour) {
- // Ensure x and y 0 is smaller than x and y 1
- --y0;
- --x0;
+ // Ensure x and y 0 is smaller than x and y 1
+ --y0;
+ --x0;
- // Draw the rectangle
- drawLine(x0,y0,x1,y0,colour); // Top
- drawLine(x0,y1,x1,y1,colour); // Bottom
- drawLine(x0,y0,x0,y1,colour); // Left
- drawLine(x1,y0,x1,y1,colour); // Right
+ // Draw the rectangle
+ drawLine(x0, y0, x1, y0, colour); // Top
+ drawLine(x0, y1, x1, y1, colour); // Bottom
+ drawLine(x0, y0, x0, y1, colour); // Left
+ drawLine(x1, y0, x1, y1, colour); // Right
}
@@ -604,8 +580,8 @@ void GraphicsContext::draw_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t
* @param y1 The y coordinate of the bottom right corner
* @param colour The colour of the rectangle
*/
-void GraphicsContext::fill_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const Colour& colour) {
- fill_rectangle(x0, y0, x1, y1, colour_to_int(colour));
+void GraphicsContext::fill_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, const Colour &colour) {
+ fill_rectangle(x0, y0, x1, y1, colour_to_int(colour));
}
/**
@@ -619,39 +595,38 @@ void GraphicsContext::fill_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t
*/
void GraphicsContext::fill_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint32_t colour) {
- // Draw from left to right
- if(y1 < y0){
- fill_rectangle(x1, y1, x0, y0, colour);
- return;
- }
-
- // Make sure the rectangle is within the height of the screen
- if(y0 < 0) y0 = 0;
- if(y1 > m_height) y1 = m_height;
-
- // Make sure the rectangle is within the width of the screen
- bool x_0_is_smaller = x0 < x1;
- int32_t x_min = x_0_is_smaller ? x0 : x1;
- int32_t x_max = x_0_is_smaller ? x1 : x0;
-
- if(x_min < 0) x_min = 0;
- if(x_max > m_width)
- x_max = m_width;
-
- // Mirror the Y axis as directly calling put_pixel will not do this
- if(mirror_y_axis)
- {
- int32_t temp = y1;
- y1 = m_height - y0 - 1;
- y0 = m_height - temp - 1;
- }
-
- // Draw the rectangle
- for(int32_t y = y0; y < y1; ++y){
- for (int32_t x = x_min; x < x_max; ++x) {
- putPixel(x, y, colour);
- }
- }
+ // Draw from left to right
+ if (y1 < y0) {
+ fill_rectangle(x1, y1, x0, y0, colour);
+ return;
+ }
+
+ // Make sure the rectangle is within the height of the screen
+ if (y0 < 0) y0 = 0;
+ if (y1 > m_height) y1 = m_height;
+
+ // Make sure the rectangle is within the width of the screen
+ bool x_0_is_smaller = x0 < x1;
+ int32_t x_min = x_0_is_smaller ? x0 : x1;
+ int32_t x_max = x_0_is_smaller ? x1 : x0;
+
+ if (x_min < 0) x_min = 0;
+ if (x_max > m_width)
+ x_max = m_width;
+
+ // Mirror the Y axis as directly calling put_pixel will not do this
+ if (mirror_y_axis) {
+ int32_t temp = y1;
+ y1 = m_height - y0 - 1;
+ y0 = m_height - temp - 1;
+ }
+
+ // Draw the rectangle
+ for (int32_t y = y0; y < y1; ++y) {
+ for (int32_t x = x_min; x < x_max; ++x) {
+ putPixel(x, y, colour);
+ }
+ }
}
@@ -663,8 +638,8 @@ void GraphicsContext::fill_rectangle(int32_t x0, int32_t y0, int32_t x1, int32_t
* @param radius The radius of the circle
* @param colour The colour of the circle
*/
-void GraphicsContext::draw_circle(int32_t x0, int32_t y0, int32_t radius, const Colour& colour){
- draw_circle(x0, y0, radius, colour_to_int(colour));
+void GraphicsContext::draw_circle(int32_t x0, int32_t y0, int32_t radius, const Colour &colour) {
+ draw_circle(x0, y0, radius, colour_to_int(colour));
}
/**
@@ -677,28 +652,28 @@ void GraphicsContext::draw_circle(int32_t x0, int32_t y0, int32_t radius, const
*/
void GraphicsContext::draw_circle(int32_t x0, int32_t y0, int32_t radius, uint32_t colour) {
- // Make sure the circle is with in the width and height of the screen
- if(x0 < 0) x0 = 0;
- if(x0 > m_width) x0 = m_width;
- if(y0 < 0) y0 = 0;
- if(y0 > m_height) y0 = m_height;
+ // Make sure the circle is with in the width and height of the screen
+ if (x0 < 0) x0 = 0;
+ if (x0 > m_width) x0 = m_width;
+ if (y0 < 0) y0 = 0;
+ if (y0 > m_height) y0 = m_height;
- // Mirror the Y axis as directly calling put_pixel will not do this
- if(mirror_y_axis)
- y0 = m_height -y0-1;
+ // Mirror the Y axis as directly calling put_pixel will not do this
+ if (mirror_y_axis)
+ y0 = m_height - y0 - 1;
- // Begin drawing at the left most point of the circle and draw a line to the right most point of the circle
- for(int32_t x = -radius; x <= radius; ++x){
+ // Begin drawing at the left most point of the circle and draw a line to the right most point of the circle
+ for (int32_t x = -radius; x <= radius; ++x) {
- // Draw a line from the top most point of the circle to the bottom most point of the circle
- for(int32_t y = -radius; y <= radius; ++y){
+ // Draw a line from the top most point of the circle to the bottom most point of the circle
+ for (int32_t y = -radius; y <= radius; ++y) {
- // If the point is within the circle, draw it but make sure it is only part of the outline
- if(x*x + y*y <= radius*radius && x*x + y*y >= (radius-1)*(radius-1))
- putPixel(x0+x,y0+y,colour);
- }
- }
+ // If the point is within the circle, draw it but make sure it is only part of the outline
+ if (x * x + y * y <= radius * radius && x * x + y * y >= (radius - 1) * (radius - 1))
+ putPixel(x0 + x, y0 + y, colour);
+ }
+ }
}
@@ -711,8 +686,8 @@ void GraphicsContext::draw_circle(int32_t x0, int32_t y0, int32_t radius, uint32
* @param radius The radius of the circle
* @param colour The colour of the circle
*/
-void GraphicsContext::fill_circle(int32_t x0, int32_t y0, int32_t radius, const Colour& colour) {
- fillCircle(x0,y0,radius, colour_to_int(colour));
+void GraphicsContext::fill_circle(int32_t x0, int32_t y0, int32_t radius, const Colour &colour) {
+ fillCircle(x0, y0, radius, colour_to_int(colour));
}
@@ -726,29 +701,29 @@ void GraphicsContext::fill_circle(int32_t x0, int32_t y0, int32_t radius, const
*/
void GraphicsContext::fillCircle(int32_t x0, int32_t y0, int32_t radius, uint32_t colour) {
- // Make sure the circle is with in the width and height of the screen
- if(x0 < 0) x0 = 0;
- if(x0 > m_width) x0 = m_width;
- if(y0 < 0) y0 = 0;
- if(y0 > m_height) y0 = m_height;
+ // Make sure the circle is with in the width and height of the screen
+ if (x0 < 0) x0 = 0;
+ if (x0 > m_width) x0 = m_width;
+ if (y0 < 0) y0 = 0;
+ if (y0 > m_height) y0 = m_height;
- // Mirror the Y axis as directly calling put_pixel will not do this
- if(mirror_y_axis)
- y0 = m_height -y0-1;
+ // Mirror the Y axis as directly calling put_pixel will not do this
+ if (mirror_y_axis)
+ y0 = m_height - y0 - 1;
- // Draw the circle
+ // Draw the circle
- // Begin drawing at the left most point of the circle and draw a line to the right most point of the circle
- for(int32_t x = -radius; x <= radius; ++x){
+ // Begin drawing at the left most point of the circle and draw a line to the right most point of the circle
+ for (int32_t x = -radius; x <= radius; ++x) {
- // Draw a line from the top most point of the circle to the bottom most point of the circle
- for(int32_t y = -radius; y <= radius; ++y){
+ // Draw a line from the top most point of the circle to the bottom most point of the circle
+ for (int32_t y = -radius; y <= radius; ++y) {
- // Only draw the pixel if it is within the circle
- if(x*x + y*y <= radius*radius)
- putPixel(x0+x,y0+y,colour);
- }
- }
+ // Only draw the pixel if it is within the circle
+ if (x * x + y * y <= radius * radius)
+ putPixel(x0 + x, y0 + y, colour);
+ }
+ }
}
/**
@@ -756,6 +731,6 @@ void GraphicsContext::fillCircle(int32_t x0, int32_t y0, int32_t radius, uint32_
*
* @return The framebuffer address
*/
-uint64_t* GraphicsContext::framebuffer_address() {
- return m_framebuffer_address;
+uint64_t *GraphicsContext::framebuffer_address() {
+ return m_framebuffer_address;
}
diff --git a/kernel/src/common/logger.cpp b/kernel/src/common/logger.cpp
index 52f1c421..59bb0004 100644
--- a/kernel/src/common/logger.cpp
+++ b/kernel/src/common/logger.cpp
@@ -4,18 +4,21 @@
#include
#include
#include
+#include
+#include
using namespace MaxOS;
using namespace MaxOS::common;
using namespace MaxOS::drivers::console;
-
Logger::Logger()
-:m_log_writers()
+: m_log_writers()
{
- // Set the logger to this
- s_active_logger = this;
+ s_active_logger = this;
+
+ // The following line is generated automatically by the MaxOS build system.
+ s_progress_total = 22;
}
@@ -30,20 +33,20 @@ Logger::~Logger() {
*
* @param output_stream The output stream to add
*/
-void Logger::add_log_writer(OutputStream* log_writer) {
+void Logger::add_log_writer(OutputStream *log_writer) {
- // If the list is not empty
- if(m_log_writer_count >= m_max_log_writers)
- return;
+ // If the list is not empty
+ if (m_log_writer_count >= m_max_log_writers)
+ return;
- // Add the output stream to the list
- m_log_writers[m_log_writer_count] = log_writer;
- m_log_writers_enabled[m_log_writer_count] = true;
- m_log_writer_count++;
+ // Add the output stream to the list
+ m_log_writers[m_log_writer_count] = log_writer;
+ m_log_writers_enabled[m_log_writer_count] = true;
+ m_log_writer_count++;
- // Print the setup info
- *this << LogLevel::INFO << "Logger setup: " << m_log_writer_count << "\n";
- *this << LogLevel::HEADER << "MaxOS v" << VERSION_STRING << " [ build " << BUILD_NUMBER << " ]\n";
+ // Print the setup info
+ *this << LogLevel::INFO << "Logger setup: " << m_log_writer_count << "\n";
+ *this << LogLevel::HEADER << "MaxOS v" << VERSION_STRING << " [ build " << BUILD_NUMBER << " ]\n";
}
@@ -52,16 +55,16 @@ void Logger::add_log_writer(OutputStream* log_writer) {
*
* @param output_stream The output stream to remove
*/
-void Logger::disable_log_writer(OutputStream* log_writer) {
+void Logger::disable_log_writer(OutputStream *log_writer) {
- // If the list is empty
- if(m_log_writer_count == 0)
- return;
+ // If the list is empty
+ if (m_log_writer_count == 0)
+ return;
- // Find the output stream in the list
- for(int i = 0; i < m_log_writer_count; i++)
- if(m_log_writers[i] == log_writer)
- m_log_writers_enabled[i] = false;
+ // Find the output stream in the list
+ for (int i = 0; i < m_log_writer_count; i++)
+ if (m_log_writers[i] == log_writer)
+ m_log_writers_enabled[i] = false;
}
/**
@@ -71,38 +74,39 @@ void Logger::disable_log_writer(OutputStream* log_writer) {
*/
void Logger::set_log_level(LogLevel log_level) {
- // Set the log level
- m_log_level = log_level;
+ // Set the log level
+ m_log_level = log_level;
- // Update the progress bar
- if(log_level == LogLevel::INFO){
- VESABootConsole::update_progress_bar((m_progress_current * 100) / s_progress_total);
- m_progress_current ++;
- }
+ // Update the progress bar
+ if (log_level == LogLevel::INFO) {
+ VESABootConsole::update_progress_bar((m_progress_current * 100) / s_progress_total);
+ m_progress_current++;
+ }
- // Print the header
- switch (log_level) {
+ // Print the header
+ switch (log_level) {
- case LogLevel::HEADER:
- *this << ANSI_COLOURS[ANSIColour::FG_Blue] << "[ BOOT ] ";
- break;
+ case LogLevel::HEADER:
+ *this << ANSI_COLOURS[ANSIColour::FG_Blue] << "[ BOOT ] ";
+ break;
- case LogLevel::INFO:
- *this << ANSI_COLOURS[ANSIColour::FG_Cyan] << "[ INFO ]" << ANSI_COLOURS[ANSIColour::FG_White] << " ";
- break;
+ case LogLevel::INFO:
+ *this << ANSI_COLOURS[ANSIColour::FG_Cyan] << "[ INFO ]" << ANSI_COLOURS[ANSIColour::FG_White] << " ";
+ break;
- case LogLevel::DEBUG:
- *this << ANSI_COLOURS[ANSIColour::FG_Yellow] << "[ DEBUG ]" << ANSI_COLOURS[ANSIColour::Reset] << " ";
- break;
+ case LogLevel::DEBUG:
+ *this << ANSI_COLOURS[ANSIColour::FG_Yellow] << "[ DEBUG ]" << ANSI_COLOURS[ANSIColour::Reset] << " ";
+ break;
- case LogLevel::WARNING:
- *this << ANSI_COLOURS[ANSIColour::FG_Yellow] << ANSI_COLOURS[FG_White] << "[ WARNING ]" << ANSI_COLOURS[ANSIColour::Reset] << " ";
- break;
+ case LogLevel::WARNING:
+ *this << ANSI_COLOURS[ANSIColour::BG_Yellow] << ANSI_COLOURS[FG_White] << "[ WARNING ]"
+ << ANSI_COLOURS[ANSIColour::Reset] << " ";
+ break;
- case LogLevel::ERROR:
- *this << ANSI_COLOURS[ANSIColour::BG_Red] << "[ ERROR ]" << ANSI_COLOURS[ANSIColour::Reset] << " ";
- break;
- }
+ case LogLevel::ERROR:
+ *this << ANSI_COLOURS[ANSIColour::BG_Red] << "[ ERROR ]" << ANSI_COLOURS[ANSIColour::Reset] << " ";
+ break;
+ }
}
@@ -113,78 +117,70 @@ void Logger::set_log_level(LogLevel log_level) {
*/
void Logger::write_char(char c) {
- // Ensure logging at this level is enabled
- if(m_log_level > s_max_log_level)
- return;
+ // Ensure logging at this level is enabled
+ if (m_log_level > s_max_log_level)
+ return;
- // Write the character to all output streams
- for(int i = 0; i < m_log_writer_count; i++)
- if(m_log_writers_enabled[i] || m_log_level == LogLevel::ERROR)
- m_log_writers[i]->write_char(c);
+ // Write the character to all output streams
+ for (int i = 0; i < m_log_writer_count; i++)
+ if (m_log_writers_enabled[i] || m_log_level == LogLevel::ERROR)
+ m_log_writers[i]->write_char(c);
}
/**
* @brief Gets the active logger
+ *
* @return The active logger
*/
-Logger& Logger::Out() {
- return *active_logger();
+Logger &Logger::Out() {
+ return *active_logger();
}
/**
* @brief Gets active logger set to task level
+ *
* @return The task logger
*/
-Logger Logger::HEADER(){
-
- // Set the log level to task
- s_active_logger->set_log_level(LogLevel::HEADER);
+Logger Logger::HEADER() {
- // Return the logger
- return Out();
+ s_active_logger->set_log_level(LogLevel::HEADER);
+ return Out();
}
/**
* @brief Gets active logger set to info level
+ *
* @return The info logger
*/
Logger Logger::INFO() {
- // Set the log level to info
- s_active_logger->set_log_level(LogLevel::INFO);
-
- // Return the logger
- return Out();
-
+ s_active_logger->set_log_level(LogLevel::INFO);
+ return Out();
}
/**
* @brief Gets active logger set to DEBUG level
+ *
* @return The debug logger
*/
Logger Logger::DEBUG() {
- // Set the log level to debug
- s_active_logger->set_log_level(LogLevel::DEBUG);
-
- // Return the logger
- return Out();
+ s_active_logger->set_log_level(LogLevel::DEBUG);
+ return Out();
}
/**
* @brief Gets active logger set to WARNING level
+ *
* @return The warning logger
*/
Logger Logger::WARNING() {
- // Set the log level to warning
- s_active_logger->set_log_level(LogLevel::WARNING);
-
- // Return the logger
- return Out();
+ s_active_logger->set_log_level(LogLevel::WARNING);
+ return Out();
}
/**
@@ -194,11 +190,8 @@ Logger Logger::WARNING() {
*/
Logger Logger::ERROR() {
- // Set the log level to error
- s_active_logger->set_log_level(LogLevel::ERROR);
-
- // Return the logger
- return Out();
+ s_active_logger->set_log_level(LogLevel::ERROR);
+ return Out();
}
@@ -208,7 +201,7 @@ Logger Logger::ERROR() {
* @return The active logger
*/
Logger *Logger::active_logger() {
- return s_active_logger;
+ return s_active_logger;
}
/**
@@ -219,65 +212,62 @@ Logger *Logger::active_logger() {
*/
void Logger::printf(char const *format, ...) {
- // Create a pointer to the data
- va_list parameters;
- va_start(parameters, format);
-
-
- // Loop through the format string
- for (; *format != '\0'; format++)
- {
-
- // If it is not a %, print the character
- if (*format != '%')
- {
- write_char(*format);
- continue;
- }
-
- // Move to the next character
- format++;
-
- switch (*format)
- {
- case 'd':
- {
- // Print a decimal
- int number = va_arg (parameters, int);
- write_int(number);
- break;
- }
- case 'x':
- {
- // Print a hex
- uint64_t number = va_arg (parameters, uint64_t );
- write_hex(number);
- break;
- }
- case 's':
- {
- // Print a string
- char* str = va_arg (parameters, char*);
- write(str);
- break;
- }
- }
- }
+ // Create a pointer to the data
+ va_list parameters;
+ va_start(parameters, format);
+
+ // Loop through the format string
+ for (; *format != '\0'; format++) {
+
+ // If it is not a %, print the character
+ if (*format != '%') {
+ write_char(*format);
+ continue;
+ }
+
+ // Move to the next character
+ format++;
+ switch (*format) {
+ case 'd': {
+ // Print a decimal
+ int number = va_arg (parameters, int);
+ write_int(number);
+ break;
+ }
+ case 'x': {
+ // Print a hex
+ uint64_t number = va_arg (parameters, uint64_t);
+ write_hex(number);
+ break;
+ }
+ case 's': {
+ // Print a string
+ char *str = va_arg (parameters, char*);
+ write(str);
+ break;
+ }
+ }
+ }
}
-#include
+/**
+ * @brief Puts the system into a panic state if the condition is false, printing the message first
+ *
+ * @param condition The condition to check if is met
+ * @param message The message to print if the condition fails
+ */
void Logger::ASSERT(bool condition, char const *message, ...) {
- // If the condition is met then everything is ok
- if(condition)
- return;
+ // If the condition is met then everything is ok
+ if (condition)
+ return;
- // Print the message
- s_active_logger -> set_log_level(LogLevel::ERROR);
- s_active_logger -> printf(message);
+ // Print the message
+ s_active_logger->set_log_level(LogLevel::ERROR);
+ s_active_logger->printf(message);
- // Hang the system
- system::CPU::PANIC("Check previous logs for more information");
+ // Hang the system
+ system::CPU::PANIC("Check previous logs for more information");
}
/**
@@ -286,29 +276,9 @@ void Logger::ASSERT(bool condition, char const *message, ...) {
* @param log_level The log level to set
* @return This logger
*/
-Logger& Logger::operator<<(LogLevel log_level) {
+Logger &Logger::operator<<(LogLevel log_level) {
- // Set the log level
- set_log_level(log_level);
-
- // Return this logger
- return *this;
-
-}
+ set_log_level(log_level);
+ return *this;
-/**
- * @brief Handles a line feed for different log levels
- */
-void Logger::lineFeed() {
-
- switch (s_active_logger -> m_log_level) {
- case LogLevel::HEADER:
- case LogLevel::INFO:
- case LogLevel::DEBUG:
- case LogLevel::WARNING:
- case LogLevel::ERROR:
- write_char('\n');
-
- }
-
-}
+}
\ No newline at end of file
diff --git a/kernel/src/common/outputStream.cpp b/kernel/src/common/outputStream.cpp
index 214242dd..e8f0cfa3 100644
--- a/kernel/src/common/outputStream.cpp
+++ b/kernel/src/common/outputStream.cpp
@@ -20,8 +20,7 @@ OutputStream::~OutputStream() = default;
*/
void OutputStream::lineFeed() {
- // write the text representation of a newline to the output stream.
- write_char('\n');
+ write_char('\n');
}
@@ -30,8 +29,8 @@ void OutputStream::lineFeed() {
*/
void OutputStream::carriageReturn() {
- // write the text representation of a carriage return to the output stream.
- write_char('\r');
+ // write the text representation of a carriage return to the output stream.
+ write_char('\r');
}
@@ -49,7 +48,7 @@ void OutputStream::clear() {
*/
void OutputStream::write(string string_to_write) {
- write(string_to_write.c_str());
+ write(string_to_write.c_str());
}
/**
@@ -57,44 +56,31 @@ void OutputStream::write(string string_to_write) {
*
* @param string_to_write The string to write to the output stream.
*/
-void OutputStream::write(const char* string_to_write){
+void OutputStream::write(const char *string_to_write) {
- // Loop through the string
- int i = 0;
- while (string_to_write[i] != '\0') {
+ int i = 0;
+ while (string_to_write[i] != '\0') {
- // Switch on the current character
- switch (string_to_write[i]) {
+ switch (string_to_write[i]) {
- // If the current character is a newline
- case '\n':
+ case '\n':
+ lineFeed();
+ break;
- // write a newline to the output stream
- lineFeed();
- break;
+ case '\r':
+ carriageReturn();
+ break;
- // If the current character is a carriage return
- case '\r':
+ case '\0':
+ return;
- // write a carriage return to the output stream
- carriageReturn();
- break;
+ default:
+ write_char(string_to_write[i]);
+ break;
-
- // If the current character is a null terminator
- case '\0':
- return;
-
- // If the current character is any other character
- default:
-
- // write the current character to the output stream
- write_char(string_to_write[i]);
- break;
-
- }
- i++;
- }
+ }
+ i++;
+ }
}
/**
@@ -113,7 +99,7 @@ void OutputStream::write_char(char) {
*/
void OutputStream::write_int(int int_to_write) {
- write(itoa(10, int_to_write));
+ write(itoa(10, int_to_write));
}
@@ -124,23 +110,20 @@ void OutputStream::write_int(int int_to_write) {
*/
void OutputStream::write_hex(uint64_t hex_to_write) {
- write(htoa(hex_to_write));
+ write(htoa(hex_to_write));
}
/**
- * @brief Writes a interger to the output stream.
+ * @brief Writes a integer to the output stream.
*
* @param int_to_write The integer to write to the output stream.
* @return The output stream.
*/
-OutputStream &OutputStream::operator << (int int_to_write) {
-
- // Call the writeInt function to write the integer to the output stream
- write_int(int_to_write);
+OutputStream &OutputStream::operator<<(int int_to_write) {
- // Return the output stream
- return *this;
+ write_int(int_to_write);
+ return *this;
}
/**
@@ -149,13 +132,10 @@ OutputStream &OutputStream::operator << (int int_to_write) {
* @param hex_to_write The hex to write to the output stream.
* @return The output stream.
*/
-OutputStream &OutputStream::operator << (uint64_t hex_to_write) {
-
- // Call the write_hex function to write the hex to the output stream
- write_hex(hex_to_write);
+OutputStream &OutputStream::operator<<(uint64_t hex_to_write) {
- // Return the output stream
- return *this;
+ write_hex(hex_to_write);
+ return *this;
}
/**
@@ -164,13 +144,10 @@ OutputStream &OutputStream::operator << (uint64_t hex_to_write) {
* @param string_to_write The string to write to the output stream.
* @return The output stream.
*/
-OutputStream &OutputStream::operator << (string string_to_write) {
+OutputStream &OutputStream::operator<<(string string_to_write) {
- // Call the write function to write the string to the output stream
- write(string_to_write);
-
- // Return the output stream
- return *this;
+ write(string_to_write);
+ return *this;
}
/**
@@ -181,11 +158,8 @@ OutputStream &OutputStream::operator << (string string_to_write) {
*/
OutputStream &OutputStream::operator<<(char char_to_write) {
- // Call the writeChar function to write the character to the output stream
- write_char(char_to_write);
-
- // Return the output stream
- return *this;
+ write_char(char_to_write);
+ return *this;
}
/**
@@ -196,10 +170,6 @@ OutputStream &OutputStream::operator<<(char char_to_write) {
*/
OutputStream &OutputStream::operator<<(char const *string_to_write) {
- // Call the write function to write the string to the output stream
- write(string_to_write);
-
- // Return the output stream
- return *this;
-}
-
+ write(string_to_write);
+ return *this;
+}
\ No newline at end of file
diff --git a/kernel/src/common/spinlock.cpp b/kernel/src/common/spinlock.cpp
index 660d6e8d..f8aecafb 100644
--- a/kernel/src/common/spinlock.cpp
+++ b/kernel/src/common/spinlock.cpp
@@ -21,13 +21,8 @@ Spinlock::~Spinlock() = default;
*/
void Spinlock::lock() {
- // Wait for the lock to be available
- acquire();
-
- // Set the lock to be locked
- m_locked = true;
-
-
+ acquire();
+ m_locked = true;
}
/**
@@ -35,12 +30,8 @@ void Spinlock::lock() {
*/
void Spinlock::unlock() {
- // Set the lock to be unlocked
- m_locked = false;
-
- // Release the lock
- release();
-
+ m_locked = false;
+ release();
}
/**
@@ -49,7 +40,7 @@ void Spinlock::unlock() {
* @return True if the spinlock is locked, false otherwise
*/
bool Spinlock::is_locked() const {
- return m_locked;
+ return m_locked;
}
@@ -57,20 +48,18 @@ bool Spinlock::is_locked() const {
* @brief Acquire the spinlock: wait until the lock is available, yielding if desired until that happens.
*/
void Spinlock::acquire() {
- while (__atomic_test_and_set(&m_locked, __ATOMIC_ACQUIRE)) {
+ while (__atomic_test_and_set(&m_locked, __ATOMIC_ACQUIRE)) {
- // Wait for the lock to be available
- if(m_should_yield)
- Scheduler::system_scheduler()->yield();
+ // Wait for the lock to be available
+ if (m_should_yield)
+ Scheduler::system_scheduler()->yield();
- // don't optimise this loop
- asm("nop");
- }
+ }
}
/**
* @brief Release the spinlock
*/
void Spinlock::release() {
- __atomic_clear(&m_locked, __ATOMIC_RELEASE);
+ __atomic_clear(&m_locked, __ATOMIC_RELEASE);
}
diff --git a/kernel/src/common/string.cpp b/kernel/src/common/string.cpp
index b3f5428b..b898bf8c 100644
--- a/kernel/src/common/string.cpp
+++ b/kernel/src/common/string.cpp
@@ -5,70 +5,129 @@
using namespace MaxOS;
-String::String()
-{
+String::String() {
- // String that only contains the null terminator
- m_string = new char[1];
- m_string[0] = '\0';
- m_length = 1;
+ // String that only contains the null terminator
+ allocate_self();
+ m_string[0] = '\0';
+ m_length = 0;
}
-String::String(char const *string)
-{
+String::String(char c) {
- // Get the length of the string, prevent longer than 10000 because this should mean somethings gone wrong
- m_length = 0;
- while (string[m_length] != '\0' && m_length <= 10000)
- m_length++;
+ // Create the memory
+ m_length = 1;
+ allocate_self();
+ // Store the char
+ m_string[0] = c;
+ m_string[m_length] = '\0';
- // Allocate memory for the string (and null terminator)
- m_string = new char[m_length + 1];
- // Copy the string
- for (int i = 0; i < m_length; i++)
- m_string[i] = string[i];
+}
+
+String::String(char const *string) {
+
+ // Get the length of the string, prevent longer than 10000 because this should mean something's gone wrong
+ m_length = 0;
+ while (string[m_length] != '\0' && m_length <= 10000)
+ m_length++;
+ allocate_self();
- // If the length is more than 10,000 Replace the end with a warning incase future use actually requires that
- const char* warning = "MAXOS: String length exceeded 10000 - might be a bug";
- if(m_length > 10000)
- for (int i = 0; i < 52; i++)
- m_string[m_length - 52 + i] = warning[i];
+ // Copy the string
+ for (int i = 0; i < m_length; i++)
+ m_string[i] = string[i];
+ // If the length is more than 10,000 Replace the end with a warning incase future use actually requires that
+ const char *warning = "MAXOS: String length exceeded 10000 - might be a bug";
+ if (m_length > 10000)
+ for (int i = 0; i < 52; i++)
+ m_string[m_length - 52 + i] = warning[i];
- // Write the null terminator
- m_string[m_length] = '\0';
+ m_string[m_length] = '\0';
}
+String::String(uint8_t const *string, int length) {
+ // Allocate memory for the string (and null terminator)
+ m_length = length;
+ allocate_self();
-String::String(int value) {
+ // Copy the string
+ for (int i = 0; i < length; i++)
+ m_string[i] = string[i];
+ // Write the null terminator
+ m_string[length] = '\0';
}
+String::String(int value) {
+
+ // Convert to a string
+ const char *str = itoa(10, value);
+ m_length = strlen(str);
+ // Create space to store
+ allocate_self();
+
+ // Store the string
+ for (int i = 0; i < m_length; i++)
+ m_string[i] = str[i];
+ m_string[m_length] = '\0';
+
+}
+
+/**
+ * @brief Constructs a string from a hex value (Excludes 0x____)
+ *
+ * @param value
+ */
String::String(uint64_t value) {
+ // Convert to a string
+ const char *str = htoa(value);
+ m_length = strlen(str);
+
+ // Create space to store
+ allocate_self();
+
+ // Store the string
+ for (int i = 0; i < m_length; i++)
+ m_string[i] = str[i];
+ m_string[m_length] = '\0';
}
String::String(float value) {
+ // Convert to a string
+ const char *str = ftoa(value);
+ m_length = strlen(str);
+ // Create space to store
+ allocate_self();
-}
+ // Store the string
+ for (int i = 0; i < m_length; i++)
+ m_string[i] = str[i];
+ m_string[m_length] = '\0';
+}
+/**
+ * @brief Copy constructor for the string
+ *
+ * @param other String to copy from
+ */
String::String(String const &other) {
- // Copy the other string
- copy(other);
+ copy(other);
}
String::~String() {
- // Free the memory
- delete[] m_string;
+ // Free the memory
+ if (!m_using_small)
+ delete[] m_string;
}
@@ -79,18 +138,16 @@ String::~String() {
*/
void String::copy(String const &other) {
- // Get the length of the string
- m_length = other.length();
-
- // Allocate memory for the string (and null terminator)
- m_string = new char[m_length + 1];
+ // Allocate memory for the string (and null terminator)
+ m_length = other.length();
+ allocate_self();
- // Copy the string
- for (int i = 0; i < m_length; i++)
- m_string[i] = other[i];
+ // Copy the string
+ for (int i = 0; i < m_length; i++)
+ m_string[i] = other[i];
- // Write the null terminator
- m_string[m_length] = '\0';
+ // Write the null terminator
+ m_string[m_length] = '\0';
}
@@ -102,41 +159,45 @@ void String::copy(String const &other) {
*/
int String::lex_value(String const &string) {
- // The sum of the ascii values of the characters in the string
- int sum = 0;
+ // Sum the ascii values of the characters in the string
+ int sum = 0;
+ for (int i = 0; i < string.length(); i++)
+ sum += string[i];
- // Add the ascii values of the characters in the string
- for (int i = 0; i < string.length(); i++)
- sum += string[i];
+ return sum;
+}
- // Return the sum
- return sum;
+/**
+ * @brief Allocates memory for the string
+ */
+void String::allocate_self() {
-}
+ // Clear the old buffer if in use
+ if (m_string && !m_using_small)
+ delete[] m_string;
+
+ // Try to use the small string buffer
+ m_using_small = m_length + 1 <= s_small_storage;
+ m_string = m_using_small ? m_small_string : new char[m_length + 1];
+}
/**
* @brief Sets the string to the other string
*
* @param other The string for this one to be updated to
- * @return String& The string
+ * @return String The string
*/
-String &String::operator = (String const &other) {
-
- // Self assignment check
- if (this == &other)
- return *this;
-
- // Free the old memory
- delete[] m_string;
+String &String::operator=(String const &other) {
- // Copy the other string
- copy(other);
-
- // Return the string
- return *this;
+ // Self assignment check
+ if (this == &other)
+ return *this;
+ // Copy the other string
+ copy(other);
+ return *this;
}
/**
@@ -144,11 +205,9 @@ String &String::operator = (String const &other) {
*
* @return The char* string
*/
-char* String::c_str() {
-
- // Return the string
- return m_string;
+char *String::c_str() {
+ return m_string;
}
/**
@@ -156,11 +215,98 @@ char* String::c_str() {
*
* @return The string as an array of characters
*/
-const char* String::c_str() const {
+const char *String::c_str() const {
- // Return the string
- return m_string;
+ return m_string;
+}
+
+/**
+ * @brief Checks if the string starts with the other string (must contain the same characters in the same order)
+ *
+ * @param other The other string
+ * @return True if the string starts with the other string, false otherwise
+ */
+bool String::starts_with(String const &other) {
+
+ // Must at least be able to fit the other string
+ if (m_length < other.length())
+ return false;
+
+ // Check if the string starts with the other string
+ for (int i = 0; i < other.length(); i++)
+ if (m_string[i] != other[i])
+ return false;
+ // No string left over to check so it must contain other
+ return true;
+}
+
+/**
+ * @brief Get a section of the string
+ *
+ * @param start The start of the substring
+ * @param length The length of the substring
+ * @return The substring or empty string if out of bounds
+ */
+String String::substring(int start, int length) const {
+
+ // Ensure the start is within bounds
+ if (start < 0 || start >= m_length)
+ return {};
+
+ // Ensure the length is within bounds
+ if (length < 0 || start + length > m_length)
+ return {};
+
+ // Allocate memory for the substring (and null terminator)
+ String substring;
+ substring.m_length = length;
+ substring.allocate_self();
+
+ // Copy the substring
+ for (int i = 0; i < length; i++)
+ substring.m_string[i] = m_string[start + i];
+
+ // Write the null terminator
+ substring.m_string[length] = '\0';
+
+ return substring;
+}
+
+/**
+ * @brief Splits the string by the delimiter
+ *
+ * @param delimiter What to split the string by
+ * @return A vector of strings that were split by the delimiter
+ */
+common::Vector String::split(String const &delimiter) const {
+ common::Vector strings;
+
+ // Go through the string and split it by the delimiter
+ int start = 0;
+ for (int i = 0; i <= m_length - delimiter.length(); i++) {
+
+ // Check if matches at this position
+ bool matches = true;
+ for (int j = 0; j < delimiter.length(); j++)
+ if (m_string[i + j] != delimiter[j]) {
+ matches = false;
+ break;
+ }
+
+ if(!matches)
+ continue;
+
+ // Add the splice of the string
+ strings.push_back(substring(start, i - start));
+ start = i + delimiter.length();
+ i += delimiter.length() - 1;
+ }
+
+ // Add the last string to the vector
+ strings.push_back(substring(start, m_length - start));
+
+ return strings;
}
/**
@@ -171,29 +317,27 @@ const char* String::c_str() const {
*/
int String::length(bool count_ansi) const {
- // If ansi characters are not to be counted
- if (count_ansi)
- return m_length;
+ // If ansi characters are not to be counted
+ if (count_ansi)
+ return m_length;
+ // Calculate the length of the string without ansi characters
+ int total_length = 0;
+ int clean_length = 0;
+ while (m_string[total_length] != '\0') {
- // Calculate the length of the string without ansi characters
- int total_length = 0;
- int clean_length = 0;
- while (m_string[total_length] != '\0'){
+ // If the character is an ansi character, skip it
+ if (m_string[total_length] == '\033')
+ while (m_string[total_length] != 'm')
+ total_length++;
- // If the character is an ansi character, skip it
- if (m_string[total_length] == '\033'){
- while (m_string[total_length] != 'm')
- total_length++;
- }
+ // Increment the length
+ clean_length++;
+ total_length++;
+ }
- // Increment the length
- clean_length++;
- total_length++;
- }
-
- // Return the length
- return clean_length;
+ // Return the length
+ return clean_length;
}
/**
@@ -204,17 +348,17 @@ int String::length(bool count_ansi) const {
*/
bool String::equals(String const &other) const {
- // Check if the lengths are equal
- if (m_length != other.length())
- return false;
+ // Check if the lengths are equal
+ if (m_length != other.length())
+ return false;
- // Check if the characters are equal
- for (int i = 0; i < m_length; i++)
- if (m_string[i] != other[i])
- return false;
+ // Check if the characters are equal
+ for (int i = 0; i < m_length; i++)
+ if (m_string[i] != other[i])
+ return false;
- // The strings are equal
- return true;
+ // The strings are equal
+ return true;
}
@@ -224,11 +368,10 @@ bool String::equals(String const &other) const {
* @param other The other string
* @return True if the strings are equal, false otherwise
*/
-bool String::operator == (String const &other) const {
-
- // Check if the strings are equal
- return equals(other);
+bool String::operator==(String const &other) const {
+ // Check if the strings are equal
+ return equals(other);
}
/**
@@ -237,15 +380,13 @@ bool String::operator == (String const &other) const {
* @param other The other string
* @return True if the strings are not equal, false otherwise
*/
-bool String::operator != (String const &other) const {
-
- // If the strings are equal, return false
- if (*this == other)
- return false;
+bool String::operator!=(String const &other) const {
- // The strings are not equal
- return true;
+ // Self assignment check
+ if (*this == other)
+ return false;
+ return !equals(other);
}
/**
@@ -254,10 +395,9 @@ bool String::operator != (String const &other) const {
* @param other The other string
* @return True if the string is less than the other, false otherwise
*/
-bool String::operator < (String const &other) const {
+bool String::operator<(String const &other) const {
- // If the sum of this is less than the sum of the other, return true
- return lex_value(*this) < lex_value(other);
+ return lex_value(*this) < lex_value(other);
}
@@ -267,10 +407,9 @@ bool String::operator < (String const &other) const {
* @param other The other string
* @return True if the string is greater than the other, false otherwise
*/
-bool String::operator > (String const &other) const {
+bool String::operator>(String const &other) const {
- // If the sum of this is greater than the sum of the other, return true
- return lex_value(*this) > lex_value(other);
+ return lex_value(*this) > lex_value(other);
}
@@ -280,10 +419,9 @@ bool String::operator > (String const &other) const {
* @param other The other string
* @return True if the string is less than or equal to the other, false otherwise
*/
-bool String::operator <= (String const &other) const {
+bool String::operator<=(String const &other) const {
- // If the sum of this is less than or equal to the sum of the other, return true
- return lex_value(*this) <= lex_value(other);
+ return lex_value(*this) <= lex_value(other);
}
@@ -293,10 +431,9 @@ bool String::operator <= (String const &other) const {
* @param other The other string
* @return True if the string is greater than or equal to the other, false otherwise
*/
-bool String::operator >= (String const &other) const {
+bool String::operator>=(String const &other) const {
- // If the sum of this is greater than or equal to the sum of the other, return true
- return lex_value(*this) >= lex_value(other);
+ return lex_value(*this) >= lex_value(other);
}
@@ -306,31 +443,26 @@ bool String::operator >= (String const &other) const {
* @param other The other string
* @return The concatenated string
*/
-String String::operator + (String const &other) const {
-
- // The concatenated string
- String concatenated;
-
- // The length of the concatenated string
- int length = m_length + other.length();
- concatenated.m_length = length;
+String String::operator+(String const &other) const {
- // Allocate memory for the concatenated string (and null terminator)
- concatenated.m_string = new char[length + 1];
+ // The concatenated string
+ String concatenated;
+ concatenated.m_length = m_length + other.length();
+ concatenated.allocate_self();
- // Copy the first string
- for (int i = 0; i < m_length; i++)
- concatenated.m_string[i] = m_string[i];
+ // Copy the first string
+ for (int i = 0; i < m_length; i++)
+ concatenated.m_string[i] = m_string[i];
- // Copy the second string
- for(int i = 0; i < other.length(); i++)
- concatenated.m_string[m_length + i] = other[i];
+ // Copy the second string
+ for (int i = 0; i < other.length(); i++)
+ concatenated.m_string[m_length + i] = other[i];
- // Write the null terminator
- concatenated.m_string[length] = '\0';
+ // Write the null terminator
+ concatenated.m_string[concatenated.m_length] = '\0';
- // Return the concatenated string
- return concatenated;
+ // Return the concatenated string
+ return concatenated;
}
/**
@@ -339,37 +471,12 @@ String String::operator + (String const &other) const {
* @param other The other string
* @return The concatenated string
*/
-String &String::operator += (String const &other) {
-
- // The concatenated string
- String concatenated;
-
- // The length of the concatenated string
- int length = m_length + other.length();
- concatenated.m_length = length;
-
- // Allocate memory for the concatenated string (and null terminator)
- concatenated.m_string = new char[length + 1];
-
- // Copy the first string
- for (int i = 0; i < m_length; i++)
- concatenated.m_string[i] = m_string[i];
-
- // Copy the second string
- for (int i = 0; i < other.length(); i++)
- concatenated.m_string[m_length + i] = other[i];
+String &String::operator+=(String const &other) {
- // Write the null terminator
- concatenated.m_string[length] = '\0';
-
- // Free the old memory
- delete[] m_string;
-
- // Copy the concatenated string
- copy(concatenated);
-
- // Return the concatenated string
- return *this;
+ // Add the other string to this string
+ String concatenated = *this + other;
+ copy(concatenated);
+ return *this;
}
@@ -379,8 +486,8 @@ String &String::operator += (String const &other) {
* @param index The index of the character
* @return The character at the specified index
*/
-char& String::operator[](int index) {
- return m_string[index];
+char &String::operator[](int index) {
+ return m_string[index];
}
@@ -390,8 +497,8 @@ char& String::operator[](int index) {
* @param index The index of the character
* @return The character at the specified index
*/
-char& String::operator[](int index) const {
- return m_string[index];
+char &String::operator[](int index) const {
+ return m_string[index];
}
/**
@@ -402,26 +509,21 @@ char& String::operator[](int index) const {
*/
String String::operator*(int times) const {
- // The repeated string
- String repeated;
-
- // The length of the repeated string
- int length = m_length * times;
- repeated.m_length = length;
-
- // Allocate memory for the repeated string (and null terminator)
- repeated.m_string = new char[length + 1];
+ // The repeated string
+ String repeated;
+ repeated.m_length = m_length * times;
+ repeated.allocate_self();
- // Copy the string
- for (int i = 0; i < times; i++)
- for (int j = 0; j < m_length; j++)
- repeated.m_string[i * m_length + j] = m_string[j];
+ // Copy the string
+ for (int i = 0; i < times; i++)
+ for (int j = 0; j < m_length; j++)
+ repeated.m_string[i * m_length + j] = m_string[j];
- // Write the null terminator
- repeated.m_string[length] = '\0';
+ // Write the null terminator
+ repeated.m_string[repeated.m_length] = '\0';
- // Return the repeated string
- return repeated;
+ // Return the repeated string
+ return repeated;
}
@@ -434,39 +536,55 @@ String String::operator*(int times) const {
*/
String String::center(int width, char fill) const {
- // The centered string
- String centered;
+ // The number of characters to add
+ int add = (width - m_length) / 2;
- // The length of the string
- int length = m_length;
+ // The centered string
+ String centered;
+ centered.m_length = width;
+ centered.allocate_self();
- // The number of characters to add
- int add = (width - length) / 2;
+ // Fill the right side (before)
+ for (int i = 0; i < add; i++)
+ centered.m_string[i] = fill;
- // The length of the centered string
- centered.m_length = width;
+ // Copy the string (middle)
+ for (int i = 0; i < m_length; i++)
+ centered.m_string[add + i] = m_string[i];
- // Allocate memory for the centered string (and null terminator)
- centered.m_string = new char[width + 1];
+ // Fill the left side (after)
+ for (int i = add + m_length; i < width; i++)
+ centered.m_string[i] = fill;
- // Fill the string with the fill character
- for (int i = 0; i < add; i++)
- centered.m_string[i] = fill;
+ // Write the null terminator
+ centered.m_string[width] = '\0';
- // Copy the string
- for (int i = 0; i < length; i++)
- centered.m_string[add + i] = m_string[i];
+ return centered;
+}
+
+/**
+ * @brief Strips the string of whitespace
+ *
+ * @param strip_char The character to strip (default = ' ')
+ * @return The stripped string (new string)
+ */
+String String::strip(char strip_char) const {
- // Fill the string with the fill character
- for (int i = add + length; i < width; i++)
- centered.m_string[i] = fill;
+ // The stripped string
+ String stripped;
+ stripped.copy(*this);
- // Write the null terminator
- centered.m_string[width] = '\0';
+ // Search from the back for the earliest non-whitespace character
+ int end = m_length - 1;
+ while (end >= 0 && (m_string[end] == strip_char || m_string[end] == '\n' || m_string[end] == '\t'))
+ end--;
- // Return the centered string
- return centered;
+ // Make sure there is something to strip
+ if (end < 0)
+ return stripped;
+ // Split the string to remove the end
+ return stripped.substring(0, end + 1);
}
/**
@@ -475,11 +593,10 @@ String String::center(int width, char fill) const {
* @param str The string to get the length of
* @return The length of the string
*/
-int strlen(const char* str)
-{
- int len = 0;
- for (; str[len] != '\0'; len++);
- return len;
+int strlen(const char *str) {
+ int len = 0;
+ for (; str[len] != '\0'; len++);
+ return len;
}
/**
@@ -491,32 +608,29 @@ int strlen(const char* str)
*
* @return The converted string
*/
-char* itoa(int base, int64_t number)
-{
+char *itoa(int base, int64_t number) {
- // If there is no buffer use a default buffer
- static char buffer[50] = {0};
+ // If there is no buffer use a default buffer
+ static char buffer[50] = {0};
- int i = 49;
- bool isNegative = number < 0;
+ int i = 49;
+ bool isNegative = number < 0;
- if (number == 0)
- {
- buffer[i] = '0';
- return &buffer[i];
- }
+ if (number == 0) {
+ buffer[i] = '0';
+ return &buffer[i];
+ }
- for (; number && i; --i, number /= base)
- buffer[i] = "0123456789ABCDEF"[number % base];
+ for (; number && i; --i, number /= base)
+ buffer[i] = "0123456789ABCDEF"[number % base];
- if (isNegative)
- {
- buffer[i] = '-';
- return &buffer[i];
- }
+ if (isNegative) {
+ buffer[i] = '-';
+ return &buffer[i];
+ }
- return &buffer[i + 1];
+ return &buffer[i + 1];
}
/**
@@ -526,22 +640,20 @@ char* itoa(int base, int64_t number)
* @param buffer The buffer to store the converted string
* @return The converted string
*/
-char* htoa(uint64_t number)
-{
- // If there is no buffer use a default buffer
- static char buffer[50] = {0};
- int i = 49;
+char *htoa(uint64_t number) {
+ // If there is no buffer use a default buffer
+ static char buffer[50] = {0};
+ int i = 49;
- if (number == 0)
- {
- buffer[i] = '0';
- return &buffer[i];
- }
+ if (number == 0) {
+ buffer[i] = '0';
+ return &buffer[i];
+ }
- for (; number && i; --i, number /= 16)
- buffer[i] = "0123456789ABCDEF"[number % 16];
+ for (; number && i; --i, number /= 16)
+ buffer[i] = "0123456789ABCDEF"[number % 16];
- return &buffer[i + 1];
+ return &buffer[i + 1];
}
/**
@@ -551,65 +663,65 @@ char* htoa(uint64_t number)
* @param buffer The buffer to store the converted string
* @return The converted string
*/
-char* ftoa(float number) {
+char *ftoa(float number) {
- static char buffer[50];
- char* ptr = buffer;
+ static char buffer[50];
+ char *ptr = buffer;
- // Handle negative numbers.
- if (number < 0) {
- *ptr++ = '-';
- number = -number;
- }
+ // Handle negative numbers.
+ if (number < 0) {
+ *ptr++ = '-';
+ number = -number;
+ }
- // Separate integer and fractional parts.
- int64_t intPart = (int64_t)number;
- float fraction = number - (float)intPart;
+ // Separate integer and fractional parts.
+ int64_t intPart = (int64_t) number;
+ float fraction = number - (float) intPart;
- // Convert integer part to string using itoa.
- char* intStr = itoa(10, intPart);
- while (*intStr) {
- *ptr++ = *intStr++;
- }
+ // Convert integer part to string using itoa.
+ char *intStr = itoa(10, intPart);
+ while (*intStr) {
+ *ptr++ = *intStr++;
+ }
- // Add the decimal point.
- *ptr++ = '.';
+ // Add the decimal point.
+ *ptr++ = '.';
- // Define the desired precision for the fractional part.
- const int precision = 6;
+ // Define the desired precision for the fractional part.
+ const int precision = 6;
- // Multiply the fraction to shift the decimal digits into integer range.
- float fracValue = fraction;
- for (int i = 0; i < precision; i++) {
- fracValue *= 10.0f;
- }
+ // Multiply the fraction to shift the decimal digits into integer range.
+ float fracValue = fraction;
+ for (int i = 0; i < precision; i++) {
+ fracValue *= 10.0f;
+ }
- // Optionally, round the value.
- auto fracInt = (int64_t)(fracValue + 0.5f);
+ // Optionally, round the value.
+ auto fracInt = (int64_t) (fracValue + 0.5f);
- // Convert the fractional part to string.
- char fracBuffer[50];
- char* fracStr = itoa(10, fracInt);
+ // Convert the fractional part to string.
+ char fracBuffer[50];
+ char *fracStr = itoa(10, fracInt);
- // Ensure we have leading zeros if the fractional part doesn't produce enough digits.
- // Calculate length of the converted fractional string.
- int len = 0;
- for (char* p = fracStr; *p; p++) {
- len++;
- }
- for (int i = 0; i < precision - len; i++) {
- *ptr++ = '0';
- }
+ // Ensure we have leading zeros if the fractional part doesn't produce enough digits.
+ // Calculate length of the converted fractional string.
+ int len = 0;
+ for (char *p = fracStr; *p; p++) {
+ len++;
+ }
+ for (int i = 0; i < precision - len; i++) {
+ *ptr++ = '0';
+ }
- // Copy the fractional digits.
- while (*fracStr) {
- *ptr++ = *fracStr++;
- }
+ // Copy the fractional digits.
+ while (*fracStr) {
+ *ptr++ = *fracStr++;
+ }
- // Null-terminate the string.
- *ptr = '\0';
+ // Null-terminate the string.
+ *ptr = '\0';
- return buffer;
+ return buffer;
}
/**
@@ -621,13 +733,13 @@ char* ftoa(float number) {
*/
bool strcmp(char const *str1, char const *str2) {
- // Check if the strings are equal
- for (int i = 0; str1[i] != '\0' || str2[i] != '\0'; i++)
- if (str1[i] != str2[i])
- return false;
+ // Check if the strings are equal
+ for (int i = 0; str1[i] != '\0' || str2[i] != '\0'; i++)
+ if (str1[i] != str2[i])
+ return false;
- // The strings are equal
- return true;
+ // The strings are equal
+ return true;
}
@@ -640,8 +752,8 @@ bool strcmp(char const *str1, char const *str2) {
*/
bool strcmp(char const *str1, String const &str2) {
- // Use the other strcmp function
- return strcmp(str1, str2.c_str());
+ // Use the other strcmp function
+ return strcmp(str1, str2.c_str());
}
@@ -654,8 +766,8 @@ bool strcmp(char const *str1, String const &str2) {
*/
bool strcmp(String const &str1, char const *str2) {
- // Use the other strcmp function
- return strcmp(str1.c_str(), str2);
+ // Use the other strcmp function
+ return strcmp(str1.c_str(), str2);
}
/**
@@ -667,8 +779,8 @@ bool strcmp(String const &str1, char const *str2) {
*/
bool strcmp(String const &str1, String const &str2) {
- // Use the other strcmp function
- return strcmp(str1.c_str(), str2.c_str());
+ // Use the other strcmp function
+ return strcmp(str1.c_str(), str2.c_str());
}
@@ -682,13 +794,13 @@ bool strcmp(String const &str1, String const &str2) {
*/
bool strncmp(char const *str1, char const *str2, int length) {
- // Check if the strings are equal
- for (int i = 0; i < length; i++)
- if (str1[i] != str2[i])
- return false;
+ // Check if the strings are equal
+ for (int i = 0; i < length; i++)
+ if (str1[i] != str2[i])
+ return false;
- // Strings are equal
- return true;
+ // Strings are equal
+ return true;
}
@@ -702,8 +814,8 @@ bool strncmp(char const *str1, char const *str2, int length) {
*/
bool strncmp(char const *str1, String const &str2, int length) {
- // Use the other strncmp function
- return strncmp(str1, str2.c_str(), length);
+ // Use the other strncmp function
+ return strncmp(str1, str2.c_str(), length);
}
@@ -717,8 +829,8 @@ bool strncmp(char const *str1, String const &str2, int length) {
*/
bool strncmp(String const &str1, char const *str2, int length) {
- // Use the other strncmp function
- return strncmp(str1.c_str(), str2, length);
+ // Use the other strncmp function
+ return strncmp(str1.c_str(), str2, length);
}
@@ -732,6 +844,6 @@ bool strncmp(String const &str1, char const *str2, int length) {
*/
bool strncmp(String const &str1, String const &str2, int length) {
- // Use the other strncmp function
- return strncmp(str1.c_str(), str2.c_str(), length);
+ // Use the other strncmp function
+ return strncmp(str1.c_str(), str2.c_str(), length);
}
diff --git a/kernel/src/drivers/clock/clock.cpp b/kernel/src/drivers/clock/clock.cpp
index 9aa8acaa..32e3e2a6 100644
--- a/kernel/src/drivers/clock/clock.cpp
+++ b/kernel/src/drivers/clock/clock.cpp
@@ -10,7 +10,6 @@ using namespace MaxOS::hardwarecommunication;
using namespace MaxOS::drivers;
using namespace MaxOS::drivers::clock;
-///__Handler__
ClockEventHandler::ClockEventHandler() = default;
@@ -31,22 +30,19 @@ void ClockEventHandler::on_time(common::Time const &) {
* @param event The event being fired
* @return The event (may have been modified by the handler)
*/
-Event* ClockEventHandler::on_event(Event* event) {
-
- switch (event -> type) {
- case ClockEvents::TIME:
- on_time(*((TimeEvent *)event)->time);
- break;
-
- default:
- break;
- }
-
- // Return the event
- return event;
-}
+Event *ClockEventHandler::on_event(Event *event) {
+
+ switch (event->type) {
+ case ClockEvents::TIME:
+ on_time(*((TimeEvent *) event)->time);
+ break;
-///__Clock__
+ default:
+ break;
+ }
+
+ return event;
+}
/**
* @brief Constructor for the Clock class
@@ -54,13 +50,12 @@ Event* ClockEventHandler::on_event(Event* event) {
* @param interrupt_manager The interrupt manager
* @param time_between_events The time between events in 10ths of a second
*/
-Clock::Clock(AdvancedProgrammableInterruptController* apic, uint16_t time_between_events)
-: Driver(),
- InterruptHandler(0x20),
+Clock::Clock(AdvancedProgrammableInterruptController *apic, uint16_t time_between_events)
+: InterruptHandler(0x20),
m_apic(apic),
m_ticks_between_events(time_between_events)
{
- Logger::INFO() << "Setting up Clock \n";
+ Logger::INFO() << "Setting up Clock \n";
}
Clock::~Clock() = default;
@@ -71,20 +66,20 @@ Clock::~Clock() = default;
*/
void Clock::handle_interrupt() {
- // Increment the number of ticks and decrement the number of ticks until the next event
- m_ticks++;
- m_ticks_until_next_event--;
+ // Clock has ticked
+ m_ticks++;
+ m_ticks_until_next_event--;
- // If the number of ticks until the next event is not 0 then return
- if(m_ticks_until_next_event != 0)
- return;
+ // Dont raise events until needed
+ if (m_ticks_until_next_event != 0)
+ return;
- // Otherwise, reset the number of ticks until the next event
- m_ticks_until_next_event = m_ticks_between_events;
-
- // Raise the time event
+ // Raise the time event
// Time time = get_time();
// raise_event(new TimeEvent(&time));
+
+ // Reset
+ m_ticks_until_next_event = m_ticks_between_events;
}
@@ -94,13 +89,10 @@ void Clock::handle_interrupt() {
* @param address The address of the register to read from
* @return The value of the register
*/
-uint8_t Clock::read_hardware_clock(uint8_t address)
-{
- // Send the address to the hardware clock
- m_command_port.write(address);
+uint8_t Clock::read_hardware_clock(uint8_t address) {
- // read the value from the hardware clock
- return m_data_port.read();
+ m_command_port.write(address);
+ return m_data_port.read();
}
/**
@@ -111,13 +103,12 @@ uint8_t Clock::read_hardware_clock(uint8_t address)
*/
uint8_t Clock::binary_representation(uint8_t number) const {
- // If the binary coded decimal representation is not used, return the number
- if(m_binary)
- return number;
-
- // Otherwise, return the binary representation
- return ((number / 16) * 10) + (number & 0x0f);
+ // Check if the conversion needed
+ if (m_binary)
+ return number;
+ // Convert to the binary representation
+ return ((number / 16) * 10) + (number & 0x0f);
}
/**
@@ -125,16 +116,16 @@ uint8_t Clock::binary_representation(uint8_t number) const {
*/
void Clock::activate() {
- // read the status register
- uint8_t status = read_hardware_clock(0xB);
+ s_active_clock = this;
- // Set the clock information
- m_24_hour_clock = status & 0x02;
- m_binary = status & 0x04;
+ // Get the stats from the clock
+ uint8_t status = read_hardware_clock(0xB);
+ // Store the clock status
+ m_24_hour_clock = status & 0x02;
+ m_binary = status & 0x04;
}
-
/**
* @brief Delays the program for a specified number of milliseconds
* (rounded up to the nearest degree of accuracy - ensured the delay is at least the specified number of milliseconds).
@@ -147,16 +138,13 @@ void Clock::activate() {
*/
void Clock::delay(uint32_t milliseconds) const {
+ // Round the number of milliseconds UP to the nearest clock accuracy
+ uint64_t rounded_milliseconds = (milliseconds + clock_accuracy - 1) / clock_accuracy;
- // Round the number of milliseconds UP to the nearest clock accuracy
- uint64_t rounded_milliseconds = (milliseconds + s_clock_accuracy - 1) / s_clock_accuracy;
-
- // Calculate the number of ticks until the delay is over
- uint64_t ticks_until_delay_is_over = m_ticks + rounded_milliseconds;
-
- // Wait until the number of ticks is equal to the number of ticks until the delay is over
- while(m_ticks < ticks_until_delay_is_over)
- asm volatile("nop");
+ // Wait until the time has passed
+ uint64_t ticks_until_delay_is_over = m_ticks + rounded_milliseconds;
+ while (m_ticks < ticks_until_delay_is_over)
+ asm volatile("nop");
}
/**
@@ -165,7 +153,7 @@ void Clock::delay(uint32_t milliseconds) const {
* @return The name of the vendor
*/
string Clock::vendor_name() {
- return "Generic";
+ return "Generic";
}
/**
@@ -174,7 +162,7 @@ string Clock::vendor_name() {
* @return The name of the device
*/
string Clock::device_name() {
- return "Clock";
+ return "Clock";
}
/**
@@ -184,27 +172,25 @@ string Clock::device_name() {
*/
void Clock::calibrate(uint64_t ms_per_tick) {
- Logger::INFO() << "Calibrating Clock \n";
+ Logger::INFO() << "Calibrating Clock \n";
+ clock_accuracy = ms_per_tick;
- // Update the clock accuracy
- s_clock_accuracy = ms_per_tick;
+ // Get the ticks per ms
+ PIT pit(m_apic);
+ uint32_t ticks_per_ms = pit.ticks_per_ms();
- // Get the ticks per ms
- PIT pit(m_apic);
- uint32_t ticks_per_ms = pit.ticks_per_ms();
+ // Configure the clock to periodic mode
+ uint32_t lvt = 0x20 | (1 << 17);
+ m_apic->local_apic()->write(0x320, lvt);
- // Set the timer vector to 0x20 and configure it for periodic mode
- uint32_t lvt = 0x20 | (1 << 17);
- m_apic -> local_apic() -> write(0x320, lvt);
+ // Set the initial count
+ m_apic->local_apic()->write(0x380, ms_per_tick * ticks_per_ms);
- // Set the initial count
- m_apic -> local_apic() -> write(0x380, ms_per_tick * ticks_per_ms);
+ // Clear the interrupt mask for the clock
+ lvt &= ~(1 << 16);
+ m_apic->local_apic()->write(0x380, lvt);
- // Clear the mask bit
- lvt &= ~(1 << 16);
- m_apic -> local_apic() -> write(0x380, lvt);
-
- Logger::DEBUG() << "Clock: Calibrated to " << ms_per_tick << "ms per tick\n";
+ Logger::DEBUG() << "Clock: Calibrated to " << ms_per_tick << "ms per tick\n";
}
/**
@@ -214,34 +200,33 @@ void Clock::calibrate(uint64_t ms_per_tick) {
*/
common::Time Clock::get_time() {
- // Wait for the clock to be ready
- while(read_hardware_clock(0xA) & 0x80)
- asm volatile("nop");
-
- // Create a time object
- Time time{};
-
- // read the time from the hardware clock
- time.year = binary_representation(read_hardware_clock(0x9)) + 2000;
- time.month = binary_representation(read_hardware_clock(0x8));
- time.day = binary_representation(read_hardware_clock(0x7));
- time.hour = binary_representation(read_hardware_clock(0x4));
- time.minute = binary_representation(read_hardware_clock(0x2));
- time.second = binary_representation(read_hardware_clock(0x0));
+ // Wait for the clock to be ready
+ while (read_hardware_clock(0xA) & 0x80)
+ asm volatile("nop");
- // If the clock is using 12hr format and PM is set then add 12 to the hour
- if(!m_24_hour_clock && (time.hour & 0x80) != 0)
- time.hour = ((time.hour & 0x7F) + 12) % 24;
+ // Read the time from the clock
+ Time time{};
+ time.year = binary_representation(read_hardware_clock(0x9)) + 2000;
+ time.month = binary_representation(read_hardware_clock(0x8));
+ time.day = binary_representation(read_hardware_clock(0x7));
+ time.hour = binary_representation(read_hardware_clock(0x4));
+ time.minute = binary_representation(read_hardware_clock(0x2));
+ time.second = binary_representation(read_hardware_clock(0x0));
+ // If the clock is using 12hr format and PM is set then add 12 to the hour
+ if (!m_24_hour_clock && (time.hour & 0x80) != 0)
+ time.hour = ((time.hour & 0x7F) + 12) % 24;
- //Raise the clock event
- return time;
+ return time;
}
+Clock *Clock::active_clock() {
+ return s_active_clock;
+}
-TimeEvent::TimeEvent(Time* time)
-:Event(ClockEvents::TIME),
-time(time)
+TimeEvent::TimeEvent(Time *time)
+: Event(ClockEvents::TIME),
+ time(time)
{
}
@@ -252,8 +237,8 @@ PIT::PIT(AdvancedProgrammableInterruptController *apic)
: InterruptHandler(0x22),
m_data_port(0x40),
m_command_port(0x43),
- m_local_apic(apic -> local_apic()),
- m_io_apic(apic -> io_apic())
+ m_local_apic(apic->local_apic()),
+ m_io_apic(apic->io_apic())
{
}
@@ -264,7 +249,7 @@ PIT::~PIT() = default;
* @brief Tick on each interrupt
*/
void PIT::handle_interrupt() {
- m_ticks++;
+ m_ticks++;
}
/**
@@ -274,56 +259,55 @@ void PIT::handle_interrupt() {
*/
uint32_t PIT::ticks_per_ms() {
- // Set the redirect for the timer interrupt
- interrupt_redirect_t redirect = {
- .type = 0x2,
- .index = 0x14,
- .interrupt = 0x22,
- .destination = 0x00,
- .flags = 0x00,
- .mask = true,
- };
- m_io_apic -> set_redirect(&redirect);
-
- // Configure the PIT clock
- pit_command_t command = {
- .bcd_mode = (uint8_t)BCDMode::BINARY,
- .operating_mode = (uint8_t)OperatingMode::RATE_GENERATOR,
- .access_mode = (uint8_t)AccessMode::LOW_HIGH_BYTE,
- .channel = (uint8_t)Channel::INTERRUPT
- };
- m_command_port.write(*(uint8_t *)&command);
-
- // Set the clock rate to 1 ms;
- uint16_t rate = 1193182 / 1000;
- m_data_port.write(rate & 0xFF);
- m_data_port.write(rate >> 8);
-
- // Stop the clock (write 0 as the initial count)
- m_local_apic -> write(0x380, 0x00);
-
- // Set the divisor to 2
- m_local_apic -> write(0x3E0, 0x0);
-
- // Unmask the PIT interrupt
- m_io_apic ->set_redirect_mask(redirect.index, false);
-
- // Calculate the number of ticks in 1 ms
- auto max = (uint32_t) - 1;
- m_local_apic -> write(0x380, max);
-
- while (m_ticks < s_calibrate_ticks)
- asm volatile("nop");
-
- uint32_t elapsed = max - (m_local_apic -> read(0x390));
- uint32_t ticks_per_ms = elapsed / s_calibrate_ticks;
-
- Logger::DEBUG() << "Ticks per ms: " << (int)ticks_per_ms << "\n";
-
- // Disable the PIT interrupt again
- m_local_apic -> write(0x380, 0x00);
- m_io_apic -> set_redirect_mask(redirect.index, true);
-
- return ticks_per_ms;
-
+ // Set the redirect for the timer interrupt
+ interrupt_redirect_t redirect = {
+ .type = 0x2,
+ .index = 0x14,
+ .interrupt = 0x22,
+ .destination = 0x00,
+ .flags = 0x00,
+ .mask = true,
+ };
+ m_io_apic->set_redirect(&redirect);
+
+ // Configure the PIT clock
+ pit_command_t command = {
+ .bcd_mode = (uint8_t) BCDMode::BINARY,
+ .operating_mode = (uint8_t) OperatingMode::RATE_GENERATOR,
+ .access_mode = (uint8_t) AccessMode::LOW_HIGH_BYTE,
+ .channel = (uint8_t) Channel::INTERRUPT
+ };
+ m_command_port.write(*(uint8_t *) &command);
+
+ // Set the clock rate to 1 ms;
+ uint16_t rate = 1193182 / 1000;
+ m_data_port.write(rate & 0xFF);
+ m_data_port.write(rate >> 8);
+
+ // Stop the clock
+ m_local_apic->write(0x380, 0x00);
+
+ // Set the divisor to 2
+ m_local_apic->write(0x3E0, 0x0);
+
+ // Unmask the PIT interrupt
+ m_io_apic->set_redirect_mask(redirect.index, false);
+
+ // Calculate the number of ticks in 1 ms
+ auto max = (uint32_t) -1;
+ m_local_apic->write(0x380, max);
+
+ while (m_ticks < s_calibrate_ticks)
+ asm volatile("nop");
+
+ uint32_t elapsed = max - (m_local_apic->read(0x390));
+ uint32_t ticks_per_ms = elapsed / s_calibrate_ticks;
+
+ Logger::DEBUG() << "Ticks per ms: " << (int) ticks_per_ms << "\n";
+
+ // Disable the PIT interrupt again
+ m_local_apic->write(0x380, 0x00);
+ m_io_apic->set_redirect_mask(redirect.index, true);
+
+ return ticks_per_ms;
}
diff --git a/kernel/src/drivers/console/console.cpp b/kernel/src/drivers/console/console.cpp
index ada5e196..43a2dbed 100644
--- a/kernel/src/drivers/console/console.cpp
+++ b/kernel/src/drivers/console/console.cpp
@@ -9,8 +9,6 @@ using namespace MaxOS::common;
using namespace MaxOS::drivers;
using namespace MaxOS::drivers::console;
-///____ Console ____
-
Console::Console() = default;
Console::~Console() = default;
@@ -131,17 +129,15 @@ void Console::put_string(uint16_t x, uint16_t y, string string, ConsoleColour fo
// Print each character on the screen
for(int i = 0; i < string.length(); i++)
- put_character(x + i, y, string[i], foreground, background);
+ put_character(x + i, y, string[i], foreground, background);
}
/**
- * @brief Scroll the console up by 1 line
+ * @brief Scroll the entire console up by 1 line
*/
void Console::scroll_up() {
- // Scroll the console up by 1 line
scroll_up(0, 0, width(), height());
-
}
/**
@@ -157,32 +153,22 @@ void Console::scroll_up() {
*/
void Console::scroll_up(uint16_t left, uint16_t top, uint16_t width, uint16_t height, ConsoleColour foreground, ConsoleColour background, char fill) {
- // For each line in the area to scroll (except the last line)
- for(uint32_t y = top; y < top+height-1; y++){
-
- // For each character in the line
- for(uint32_t x = left; x < left+width; x++) {
+ // Shift everything but the last line by getting what is below it
+ for(uint32_t y = top; y < top+height-1; y++)
+ for(uint32_t x = left; x < left+width; x++)
+ put_character(x, y, get_character(x, y + 1), get_foreground_color(x, y + 1), get_background_color(x, y + 1));
- // Put the character from the line below
- put_character(x, y, get_character(x, y + 1),
- get_foreground_color(x, y + 1),
- get_background_color(x, y + 1));
-
- }
- }
-
- // Fill the last line with the fill character
+ // Fill the last line
for(uint16_t x = left; x < left+width; x++)
put_character(x, top + height - 1, fill, foreground, background);
}
/**
- * Clear the console
+ * Clear the entire console
*/
void Console::clear() {
- // Clear the console
clear(0, 0, width(), height());
}
@@ -200,11 +186,14 @@ void Console::clear() {
*/
void Console::clear(uint16_t left, uint16_t top, uint16_t width, uint16_t height, ConsoleColour foreground, ConsoleColour background, char fill) {
- // Put the fill character in the areas
- for(uint16_t y = top; y < top+height; y++)
- for(uint16_t x = left; x < left+width; x++){
+ // Check bounds
+ if ( left > this -> width() || top > this -> height() || width > this -> width() || height > this -> height() )
+ return;
+
+ // Fill the area with the character
+ for(uint16_t y = top; y < top + height; y++)
+ for(uint16_t x = left; x < left + width; x++)
put_character(x, y, fill, foreground, background);
- }
}
@@ -225,10 +214,6 @@ void Console::invert_colors(uint16_t x, uint16_t y) {
set_background_color(x, y, foreground);
}
-
-///____ Console Area ____///
-
-
ConsoleArea::ConsoleArea(Console *console, uint16_t left, uint16_t top, uint16_t width, uint16_t height)
: m_console(console),
m_left(left),
@@ -247,7 +232,7 @@ ConsoleArea::ConsoleArea(Console *console, uint16_t left, uint16_t top, uint16_t
m_height(height)
{
- // Loop through the area setting the colors
+ // Store the colours of the console
for(uint16_t y = top; y < top+height; y++)
for(uint16_t x = left; x < left+width; x++){
console->set_foreground_color(x, y, foreground);
@@ -256,7 +241,6 @@ ConsoleArea::ConsoleArea(Console *console, uint16_t left, uint16_t top, uint16_t
}
-
ConsoleArea::~ConsoleArea() = default;
/**
@@ -286,13 +270,12 @@ uint16_t ConsoleArea::height() {
*/
void ConsoleArea::put_character(uint16_t x, uint16_t y, char c) {
- // Make sure the coordinates are within the console area
+ // Check bounds
if(x >= m_width || y >= m_height)
return;
- // Put the character on the console
+ // Write to the console
m_console->put_character(m_left + x, m_top + y, c);
-
}
@@ -389,9 +372,7 @@ ConsoleColour ConsoleArea::get_background_color(uint16_t x, uint16_t y) {
*/
void ConsoleArea::scroll_up() {
- // Get the console
m_console->scroll_up(m_left, m_top, m_width, m_height);
-
}
/**
@@ -413,7 +394,6 @@ void ConsoleArea::scroll_up(uint16_t left, uint16_t top, uint16_t width,
}
-///____ Console Stream ____///
ConsoleStream::ConsoleStream(Console *console)
: m_console(console)
{
@@ -446,13 +426,11 @@ void ConsoleStream::write_char(char c) {
switch (c) {
// New line
case '\n':
- // Increment the y coordinate but if it is more than the height of the console scroll the console
+ // Go to the next line, if it is more then what the console can fit then scroll
if(++m_cursor_y >= m_console->height()){
-
- // Scroll the console
m_console->scroll_up();
- // Decrement the y coordinate
+ // Ensure there is space at the bottom to write
m_cursor_y = m_console->height()-1;
}
@@ -461,23 +439,22 @@ void ConsoleStream::write_char(char c) {
// Carriage return
case '\r':
- // Go to the start of the next line
m_cursor_x = 0;
break;
- // Null Terminator
+ // End of string
case '\0':
break;
// Backspace
case '\b':
- // Decrement the x coordinate
m_cursor_x--;
break;
// Tab
case '\t':
- // Figure out how many spaces to the next tab stop
+
+ // Pad with spaces until a tab is reached
spaces = 8 - (m_cursor_x % 8);
for(uint16_t i = 0; i < spaces; i++)
write_char(' ');
@@ -487,7 +464,7 @@ void ConsoleStream::write_char(char c) {
// Put the character on the console
m_console->put_character(m_cursor_x, m_cursor_y, c);
- // Increment the x coordinate
+ // Increment the x coordinate (ANSI aren't rendered)
if(!is_ansi)
m_cursor_x++;
diff --git a/kernel/src/drivers/console/serial.cpp b/kernel/src/drivers/console/serial.cpp
index ffd36cd7..c0013b1d 100644
--- a/kernel/src/drivers/console/serial.cpp
+++ b/kernel/src/drivers/console/serial.cpp
@@ -7,7 +7,7 @@
using namespace MaxOS;
using namespace MaxOS::drivers;
-SerialConsole::SerialConsole(Logger* logger)
+SerialConsole::SerialConsole(Logger *logger)
: m_data_port(0x3F8),
m_interrupt_enable_port(0x3F9),
m_fifo_control_port(0x3FA),
@@ -16,44 +16,39 @@ SerialConsole::SerialConsole(Logger* logger)
m_line_status_port(0x3FD)
{
- // Disable all interrupts
- m_interrupt_enable_port.write(0x00);
+ // Disable all interrupts
+ m_interrupt_enable_port.write(0x00);
- // Enable DLAB (set baud rate divisor)
- m_line_control_port.write(0x80);
+ // Enable DLAB (set baud rate divisor)
+ m_line_control_port.write(0x80);
- // Set divisor to 3
- m_data_port.write(0x03);
- m_interrupt_enable_port.write(0x00);
+ // Set divisor to 3
+ m_data_port.write(0x03);
+ m_interrupt_enable_port.write(0x00);
- // 8 bits, no parity, one stop bit
- m_line_control_port.write(0x03);
+ // 8 bits, no parity, one stop bit
+ m_line_control_port.write(0x03);
- // Enable FIFO, clear them, with 14-byte threshold
- m_fifo_control_port.write(0xC7);
+ // Enable FIFO, clear them, with 14-byte threshold
+ m_fifo_control_port.write(0xC7);
- // IRQs enabled, RTS/DSR set
- m_modem_control_port.write(0x0B);
+ // IRQs enabled, RTS/DSR set
+ m_modem_control_port.write(0x0B);
- // Test serial chip
- m_modem_control_port.write(0x1E);
- m_data_port.write(0xAE);
- if (m_data_port.read() != 0xAE)
- return;
-
- // Enable serial chip
- m_modem_control_port.write(0x0F);
-
- // Set the active serial console
- logger->add_log_writer(this);
+ // Test serial chip
+ m_modem_control_port.write(0x1E);
+ m_data_port.write(0xAE);
+ if (m_data_port.read() != 0xAE)
+ return;
+ // Enable serial chip
+ m_modem_control_port.write(0x0F);
+ // Set the active serial console
+ logger->add_log_writer(this);
}
-SerialConsole::~SerialConsole() {
-
-
-}
+SerialConsole::~SerialConsole() = default;
/**
* @brief Waits for the serial port to be ready, then writes a character to it
@@ -62,13 +57,14 @@ SerialConsole::~SerialConsole() {
*/
void SerialConsole::put_character(char c) {
- // Wait for the serial port to be ready
- while (0 == (m_line_status_port.read() & 0x20));
+ // Wait for the serial port to be ready
+ while (0 == (m_line_status_port.read() & 0x20));
- // Write the character
- m_data_port.write(c);
+ // Write the character
+ m_data_port.write(c);
}
+
void SerialConsole::write_char(char c) {
- put_character(c);
-}
+ put_character(c);
+}
\ No newline at end of file
diff --git a/kernel/src/drivers/console/textmode.cpp b/kernel/src/drivers/console/textmode.cpp
index 0855e1a8..56fce4f4 100644
--- a/kernel/src/drivers/console/textmode.cpp
+++ b/kernel/src/drivers/console/textmode.cpp
@@ -9,12 +9,7 @@ using namespace MaxOS::common;
using namespace MaxOS::drivers;
using namespace MaxOS::drivers::console;
-TextModeConsole::TextModeConsole()
-: Driver(),
- Console()
-{
-
-}
+TextModeConsole::TextModeConsole() = default;
TextModeConsole::~TextModeConsole() = default;
@@ -23,9 +18,8 @@ TextModeConsole::~TextModeConsole() = default;
*
* @return The width of the console in characters
*/
-uint16_t TextModeConsole::width()
-{
- return 80;
+uint16_t TextModeConsole::width() {
+ return 80;
}
/**
@@ -33,9 +27,8 @@ uint16_t TextModeConsole::width()
*
* @return The height of the console in characters
*/
-uint16_t TextModeConsole::height()
-{
- return 25;
+uint16_t TextModeConsole::height() {
+ return 25;
}
/**
@@ -47,16 +40,15 @@ uint16_t TextModeConsole::height()
*/
void TextModeConsole::put_character(uint16_t x, uint16_t y, char c) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return;
+ // Check bounds
+ if (x >= width() || y >= height())
+ return;
- // Calculate the offset
- int offset = (y*width() + x);
-
- // Set the character at the offset, by masking the character with the current character (last 8 bits)
- m_video_memory[offset] = (m_video_memory[offset] & 0xFF00) | (uint16_t)c;
+ // Calculate the offset
+ int offset = (y * width() + x);
+ // Set the character at the offset, mask away the colour information
+ m_video_memory[offset] = (m_video_memory[offset] & 0xFF00) | (uint16_t) c;
}
/**
@@ -68,15 +60,15 @@ void TextModeConsole::put_character(uint16_t x, uint16_t y, char c) {
*/
void TextModeConsole::set_foreground_color(uint16_t x, uint16_t y, ConsoleColour foreground) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return;
+ // Check bounds
+ if (x >= width() || y >= height())
+ return;
- // Calculate the offset
- int offset = (y* width() + x);
+ // Calculate the offset
+ int offset = (y * width() + x);
- // Set the foreground color at the offset, by masking the foreground color with the current foreground color (bits 8-11)
- m_video_memory[offset] = (m_video_memory[offset] & 0xF0FF) | ((uint16_t)foreground << 8);
+ // Set the foreground color at the offset, mask to get the foreground bits
+ m_video_memory[offset] = (m_video_memory[offset] & 0xF0FF) | ((uint16_t) foreground << 8);
}
/**
@@ -88,16 +80,15 @@ void TextModeConsole::set_foreground_color(uint16_t x, uint16_t y, ConsoleColour
*/
void TextModeConsole::set_background_color(uint16_t x, uint16_t y, ConsoleColour background) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return;
-
- // Calculate the offset
- int offset = (y* width() + x);
+ // Check bounds
+ if (x >= width() || y >= height())
+ return;
- // Set the background color at the offset, by masking the background color with the current background color (bits 12-15)
- m_video_memory[offset] = (m_video_memory[offset] & 0x0FFF) | ((uint16_t)background << 12);
+ // Calculate the offset
+ int offset = (y * width() + x);
+ // Set the background color at the offset, mask to get the backgroun bits
+ m_video_memory[offset] = (m_video_memory[offset] & 0x0FFF) | ((uint16_t) background << 12);
}
/**
@@ -109,15 +100,15 @@ void TextModeConsole::set_background_color(uint16_t x, uint16_t y, ConsoleColour
*/
char TextModeConsole::get_character(uint16_t x, uint16_t y) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return ' ';
+ // Check bounds
+ if (x >= width() || y >= height())
+ return ' ';
- // Calculate the offset
- int offset = (y* width() + x);
+ // Calculate the offset
+ int offset = (y * width() + x);
- // Return the character at the offset, by masking the character with the current character (last 8 bits)
- return (char)(m_video_memory[offset] & 0x00FF);
+ // Return the character at the offset, mask away the colour information
+ return (char) (m_video_memory[offset] & 0x00FF);
}
/**
@@ -129,15 +120,15 @@ char TextModeConsole::get_character(uint16_t x, uint16_t y) {
*/
ConsoleColour TextModeConsole::get_foreground_color(uint16_t x, uint16_t y) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return ConsoleColour::White;
+ // Check bounds
+ if (x >= width() || y >= height())
+ return ConsoleColour::White;
- // Calculate the offset
- int offset = (y* width() + x);
+ // Calculate the offset
+ int offset = (y * width() + x);
- // Return the foreground color at the offset, by masking the foreground color with the current foreground color (bits 8-11)
- return (ConsoleColour)((m_video_memory[offset] & 0x0F00) >> 8);
+ // Return the foreground color at the offset, by masking the foreground color with the current foreground color (bits 8-11)
+ return (ConsoleColour) ((m_video_memory[offset] & 0x0F00) >> 8);
}
/**
@@ -149,13 +140,13 @@ ConsoleColour TextModeConsole::get_foreground_color(uint16_t x, uint16_t y) {
*/
ConsoleColour TextModeConsole::get_background_color(uint16_t x, uint16_t y) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return ConsoleColour::Black;
+ // Check bounds
+ if (x >= width() || y >= height())
+ return ConsoleColour::Black;
- // Calculate the offset
- int offset = (y* width() + x);
+ // Calculate the offset
+ int offset = (y * width() + x);
- // Return the background color at the offset, by masking the background color with the current background color (bits 12-15)
- return (ConsoleColour)((m_video_memory[offset] & 0xF000) >> 12);
+ // Return the background color at the offset, by masking the background color with the current background color (bits 12-15)
+ return (ConsoleColour) ((m_video_memory[offset] & 0xF000) >> 12);
}
\ No newline at end of file
diff --git a/kernel/src/drivers/console/vesaboot.cpp b/kernel/src/drivers/console/vesaboot.cpp
index 10159dcd..a7a063ff 100644
--- a/kernel/src/drivers/console/vesaboot.cpp
+++ b/kernel/src/drivers/console/vesaboot.cpp
@@ -15,28 +15,28 @@ using namespace MaxOS::drivers::console;
using namespace MaxOS::system;
VESABootConsole::VESABootConsole(GraphicsContext *graphics_context)
-: m_font((uint8_t*)AMIGA_FONT)
+: m_font((uint8_t *)AMIGA_FONT)
{
- // Set up
- Logger::INFO() << "Setting up VESA console\n";
- s_graphics_context = graphics_context;
- m_video_memory_meta = (uint16_t*)MemoryManager::kmalloc(width() * height() * sizeof(uint16_t));
-
- // Prepare the console
- VESABootConsole::clear();
- print_logo();
-
- // Connect to the loggers
- m_console_area = new ConsoleArea(this, 0, 0, width() / 2 - 25, height(), ConsoleColour::DarkGrey, ConsoleColour::Black);
- cout = new ConsoleStream(m_console_area);
-
- #ifdef TARGET_DEBUG
- Logger::active_logger() -> add_log_writer(cout);
- Logger::INFO() << "Console Stream set up \n";
- #endif
-
- update_progress_bar(0);
+ // Set up
+ Logger::INFO() << "Setting up VESA console\n";
+ s_graphics_context = graphics_context;
+ m_video_memory_meta = (uint16_t *) MemoryManager::kmalloc(width() * height() * sizeof(uint16_t));
+
+ // Prepare the console
+ VESABootConsole::clear();
+ print_logo();
+ m_console_area = new ConsoleArea(this, 0, 0, width() / 2 - 25, height(), ConsoleColour::DarkGrey,
+ ConsoleColour::Black);
+ cout = new ConsoleStream(m_console_area);
+
+ // Only log to the screen when debugging
+ #ifdef TARGET_DEBUG
+ Logger::active_logger()->add_log_writer(cout);
+ Logger::INFO() << "Console Stream set up \n";
+ #endif
+
+ update_progress_bar(0);
}
VESABootConsole::~VESABootConsole() = default;
@@ -46,9 +46,8 @@ VESABootConsole::~VESABootConsole() = default;
*
* @return The width of the console in characters
*/
-uint16_t VESABootConsole::width()
-{
- return s_graphics_context->width() / 8; // 8 pixels per character
+uint16_t VESABootConsole::width() {
+ return s_graphics_context->width() / 8; // 8 pixels per character
}
/**
@@ -56,9 +55,8 @@ uint16_t VESABootConsole::width()
*
* @return The height of the console in characters
*/
-uint16_t VESABootConsole::height()
-{
- return s_graphics_context->height() / Font::font_height;
+uint16_t VESABootConsole::height() {
+ return s_graphics_context->height() / Font::font_height;
}
/**
@@ -70,71 +68,68 @@ uint16_t VESABootConsole::height()
*/
void VESABootConsole::put_character(uint16_t x, uint16_t y, char c) {
- // Parse any ansi codes
- if (c == '\033') {
-
- // Store the character
- ansi_code_length = 0;
- ansi_code[ansi_code_length++] = c;
+ // Parse any ansi codes
+ if (c == '\033') {
- // Do not draw the escape character
- return;
+ // Store the character
+ ansi_code_length = 0;
+ ansi_code[ansi_code_length++] = c;
- } else if (ansi_code_length < 8) {
+ // Do not draw the escape character
+ return;
+ }
- // Add the character to the ANSI code
- ansi_code[ansi_code_length++] = c;
+ if (ansi_code_length < 8) {
- // If the ANSI code is complete
- if (c == 'm') {
- ansi_code[ansi_code_length] = '\0';
- ansi_code_length = -1;
+ // Add the character to the ANSI code
+ ansi_code[ansi_code_length++] = c;
- if(strcmp("\033[0m", ansi_code) != 0) {
- m_foreground_color = ConsoleColour::Uninitialised;
- m_background_color = ConsoleColour::Uninitialised;
- return;
- }
+ // If the ANSI code is complete
+ if (c == 'm') {
+ ansi_code[ansi_code_length] = '\0';
+ ansi_code_length = -1;
- // Get the colour from the ANSI code
- auto* colour = new Colour(ansi_code);
+ if (strcmp("\033[0m", ansi_code) != 0) {
+ m_foreground_color = ConsoleColour::Uninitialised;
+ m_background_color = ConsoleColour::Uninitialised;
+ return;
+ }
- // Set the colour
- bool foreground = ansi_code[4] == '3';
- if (foreground)
- m_foreground_color = colour->to_console_colour();
- else
- m_background_color = colour->to_console_colour();
+ // Get the colour from the ANSI code
+ const Colour colour(ansi_code);
- // Delete the colour
- delete colour;
+ // Set the colour
+ bool foreground = ansi_code[4] == '3';
+ if (foreground)
+ m_foreground_color = colour.to_console_colour();
+ else
+ m_background_color = colour.to_console_colour();
- }
+ }
- // Do not draw the escape character
- return;
- }
+ // Do not draw the escape character
+ return;
+ }
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return;
+ // If the coordinates are out of bounds, return
+ if (x >= width() || y >= height())
+ return;
- // Calculate the offset
- int offset = (y* width() + x);
+ // Calculate the offset
+ int offset = (y * width() + x);
- // Set the character at the offset, by masking the character with the current character (last 8 bits)
- m_video_memory_meta[offset] = (m_video_memory_meta[offset] & 0xFF00) | (uint16_t)c;
+ // Set the character at the offset, by masking the character with the current character (last 8 bits)
+ m_video_memory_meta[offset] = (m_video_memory_meta[offset] & 0xFF00) | (uint16_t) c;
- // Convert the char into a string
- char s[] = " ";
- s[0] = c;
+ // Convert the char into a string
+ char s[] = " ";
+ s[0] = c;
- Colour foreground = m_foreground_color == ConsoleColour::Uninitialised ? get_foreground_color(x, y) : Colour(m_foreground_color);
- Colour background = m_background_color == ConsoleColour::Uninitialised ? get_background_color(x, y) : Colour(m_background_color);
-
- // Use the m_font to draw the character
- m_font.draw_text(x * 8, y * Font::font_height, foreground, background, s_graphics_context, s);
+ Colour foreground = m_foreground_color == ConsoleColour::Uninitialised ? get_foreground_color(x, y) : Colour(m_foreground_color);
+ Colour background = m_background_color == ConsoleColour::Uninitialised ? get_background_color(x, y) : Colour(m_background_color);
+ // Use the m_font to draw the character
+ m_font.draw_text(x * 8, y * Font::font_height, foreground, background, s_graphics_context, s);
}
/**
@@ -146,15 +141,15 @@ void VESABootConsole::put_character(uint16_t x, uint16_t y, char c) {
*/
void VESABootConsole::set_foreground_color(uint16_t x, uint16_t y, ConsoleColour foreground) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return;
+ // If the coordinates are out of bounds, return
+ if (x >= width() || y >= height())
+ return;
- // Calculate the offset
- int offset = (y* width() + x);
+ // Calculate the offset
+ int offset = (y * width() + x);
- // Set the foreground color at the offset, by masking the foreground color with the current foreground color (bits 8-11)
- m_video_memory_meta[offset] = (m_video_memory_meta[offset] & 0xF0FF) | ((uint16_t)foreground << 8);
+ // Set the foreground color at the offset, by masking the foreground color with the current foreground color (bits 8-11)
+ m_video_memory_meta[offset] = (m_video_memory_meta[offset] & 0xF0FF) | ((uint16_t) foreground << 8);
}
/**
@@ -166,16 +161,15 @@ void VESABootConsole::set_foreground_color(uint16_t x, uint16_t y, ConsoleColour
*/
void VESABootConsole::set_background_color(uint16_t x, uint16_t y, ConsoleColour background) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return;
-
- // Calculate the offset
- int offset = (y* width() + x);
+ // If the coordinates are out of bounds, return
+ if (x >= width() || y >= height())
+ return;
- // Set the background color at the offset, by masking the background color with the current background color (bits 12-15)
- m_video_memory_meta[offset] = (m_video_memory_meta[offset] & 0x0FFF) | ((uint16_t)background << 12);
+ // Calculate the offset
+ int offset = (y * width() + x);
+ // Set the background color at the offset, by masking the background color with the current background color (bits 12-15)
+ m_video_memory_meta[offset] = (m_video_memory_meta[offset] & 0x0FFF) | ((uint16_t) background << 12);
}
/**
@@ -187,15 +181,15 @@ void VESABootConsole::set_background_color(uint16_t x, uint16_t y, ConsoleColour
*/
char VESABootConsole::get_character(uint16_t x, uint16_t y) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return ' ';
+ // If the coordinates are out of bounds, return
+ if (x >= width() || y >= height())
+ return ' ';
- // Calculate the offset
- int offset = (y* width() + x);
+ // Calculate the offset
+ int offset = (y * width() + x);
- // Return the character at the offset, by masking the character with the current character (last 8 bits)
- return (char)(m_video_memory_meta[offset] & 0x00FF);
+ // Return the character at the offset, by masking the character with the current character (last 8 bits)
+ return (char) (m_video_memory_meta[offset] & 0x00FF);
}
/**
@@ -207,15 +201,15 @@ char VESABootConsole::get_character(uint16_t x, uint16_t y) {
*/
ConsoleColour VESABootConsole::get_foreground_color(uint16_t x, uint16_t y) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return ConsoleColour::White;
+ // If the coordinates are out of bounds, return
+ if (x >= width() || y >= height())
+ return ConsoleColour::White;
- // Calculate the offset
- int offset = (y* width() + x);
+ // Calculate the offset
+ int offset = (y * width() + x);
- // Return the foreground color at the offset, by masking the foreground color with the current foreground color (bits 8-11)
- return (ConsoleColour)((m_video_memory_meta[offset] & 0x0F00) >> 8);
+ // Return the foreground color at the offset, by masking the foreground color with the current foreground color (bits 8-11)
+ return (ConsoleColour) ((m_video_memory_meta[offset] & 0x0F00) >> 8);
}
/**
@@ -227,15 +221,15 @@ ConsoleColour VESABootConsole::get_foreground_color(uint16_t x, uint16_t y) {
*/
ConsoleColour VESABootConsole::get_background_color(uint16_t x, uint16_t y) {
- // If the coordinates are out of bounds, return
- if(x >= width() || y >= height())
- return ConsoleColour::Black;
+ // If the coordinates are out of bounds, return
+ if (x >= width() || y >= height())
+ return ConsoleColour::Black;
- // Calculate the offset
- int offset = (y* width() + x);
+ // Calculate the offset
+ int offset = (y * width() + x);
- // Return the background color at the offset, by masking the background color with the current background color (bits 12-15)
- return (ConsoleColour)((m_video_memory_meta[offset] & 0xF000) >> 12);
+ // Return the background color at the offset, by masking the background color with the current background color (bits 12-15)
+ return (ConsoleColour) ((m_video_memory_meta[offset] & 0xF000) >> 12);
}
/**
@@ -243,29 +237,29 @@ ConsoleColour VESABootConsole::get_background_color(uint16_t x, uint16_t y) {
*/
void VESABootConsole::print_logo() {
- // Load the logo
- const char* logo = header_data;
+ // Load the logo
+ const char *logo = header_data;
- // Find the center of the screen
- uint32_t center_x = s_graphics_context->width()/2;
- uint32_t center_y = s_graphics_context->height()/2 - 80;
+ // Find the center of the screen
+ uint32_t center_x = s_graphics_context->width() / 2;
+ uint32_t center_y = s_graphics_context->height() / 2 - 80;
- // Draw the logo
- for (uint32_t logoY = 0; logoY < logo_height; ++logoY) {
- for (uint32_t logoX = 0; logoX < logo_width; ++logoX) {
+ // Draw the logo
+ for (uint32_t logoY = 0; logoY < logo_height; ++logoY) {
+ for (uint32_t logoX = 0; logoX < logo_width; ++logoX) {
- // Store the pixel in the logo
- uint8_t pixel[3] = {0};
+ // Store the pixel in the logo
+ uint8_t pixel[3] = {0};
- // Get the pixel from the logo
- LOGO_HEADER_PIXEL(logo, pixel)
+ // Get the pixel from the logo
+ LOGO_HEADER_PIXEL(logo, pixel)
- // Draw the pixel
- s_graphics_context->put_pixel(center_x - logo_width / 2 + logoX,
- center_y - logo_height / 2 + logoY,
- common::Colour(pixel[0], pixel[1], pixel[2]));
- }
- }
+ // Draw the pixel
+ s_graphics_context->put_pixel(center_x - logo_width / 2 + logoX,
+ center_y - logo_height / 2 + logoY,
+ common::Colour(pixel[0], pixel[1], pixel[2]));
+ }
+ }
}
@@ -281,57 +275,55 @@ void VESABootConsole::print_logo() {
* @param fill The character to fill the new line with
*/
void VESABootConsole::scroll_up(uint16_t left, uint16_t top, uint16_t width,
- uint16_t height,
- common::ConsoleColour foreground,
- common::ConsoleColour background, char) {
-
-
- // Get the framebuffer info
- auto* framebuffer_address = (uint8_t*)s_graphics_context->framebuffer_address();
- uint64_t framebuffer_width = s_graphics_context->width();
- uint64_t framebuffer_height = s_graphics_context->height();
- uint64_t framebuffer_bpp = s_graphics_context->color_depth(); // in bits per pixel
- uint64_t bytes_per_pixel = framebuffer_bpp / 8;
- uint64_t framebuffer_pitch = framebuffer_width * bytes_per_pixel;
-
- // Calculate the number of pixels per line
- uint16_t line_height = Font::font_height;
-
- // Calculate the number of pixels in the region
- uint16_t region_pixel_y = top * line_height;
- uint16_t region_pixel_height = height * line_height;
- uint16_t region_pixel_left = left * Font::font_width;
- uint16_t region_pixel_width = width * Font::font_width;
- size_t row_bytes = region_pixel_width * bytes_per_pixel;
-
- // Decide the colour of the pixel
- ConsoleColour to_set_foreground = CPU::is_panicking ? ConsoleColour::White : get_foreground_color(left, top + height - 1);
- ConsoleColour to_set_background = CPU::is_panicking ? ConsoleColour::Red : get_background_color(left, top + height - 1);
- Colour fill_colour = Colour(to_set_background);
- uint32_t fill_value = s_graphics_context->colour_to_int(to_set_background);
-
- // Scroll the region upward by one text line
- for (uint16_t row = 0; row < region_pixel_height - line_height; row++) {
- uint8_t* src = framebuffer_address + (region_pixel_y + row + line_height) * framebuffer_pitch + region_pixel_left * bytes_per_pixel;
- uint8_t* dest = framebuffer_address + (region_pixel_y + row) * framebuffer_pitch + region_pixel_left * bytes_per_pixel;
- memmove(dest, src, row_bytes);
- }
-
- // Clear the last line of the region
- uint16_t clear_start_y = region_pixel_y + region_pixel_height - line_height;
- for (uint16_t row = 0; row < line_height; row++) {
- auto row_add = (uint32_t*)(framebuffer_address + (clear_start_y + row) * framebuffer_pitch + region_pixel_left * 4);
- for (uint16_t col = 0; col < region_pixel_width; col++) {
- row_add[col] = fill_value;
- }
- }
-
- //Update any per-pixel colour metadata
- uint16_t text_row = top + height - 1;
- for (uint16_t x = left; x < left + width; x++) {
- set_foreground_color(x, text_row, to_set_foreground);
- set_background_color(x, text_row, to_set_background);
- }
+ uint16_t height,
+ common::ConsoleColour foreground,
+ common::ConsoleColour background, char fill) {
+
+
+ // Get the framebuffer info
+ auto *framebuffer_address = (uint8_t *) s_graphics_context->framebuffer_address();
+ uint64_t framebuffer_width = s_graphics_context->width();
+ uint64_t framebuffer_bpp = s_graphics_context->color_depth(); // in bits per pixel
+ uint64_t bytes_per_pixel = framebuffer_bpp / 8;
+ uint64_t framebuffer_pitch = framebuffer_width * bytes_per_pixel;
+
+ uint16_t line_height = Font::font_height;
+
+ // Region conversions
+ uint16_t region_pixel_y = top * line_height;
+ uint16_t region_pixel_height = height * line_height;
+ uint16_t region_pixel_left = left * Font::font_width;
+ uint16_t region_pixel_width = width * Font::font_width;
+ size_t row_bytes = region_pixel_width * bytes_per_pixel;
+
+ // Decide the colour of the pixel
+ ConsoleColour to_set_foreground = CPU::is_panicking ? ConsoleColour::White : get_foreground_color(left, top + height - 1);
+ ConsoleColour to_set_background = CPU::is_panicking ? ConsoleColour::Red : get_background_color(left, top + height - 1);
+ Colour fill_colour = Colour(to_set_background);
+ uint32_t fill_value = s_graphics_context->colour_to_int(to_set_background);
+
+ // Scroll the region upward by one text line
+ for (uint16_t row = 0; row < region_pixel_height - line_height; row++) {
+ uint8_t *src = framebuffer_address + (region_pixel_y + row + line_height) * framebuffer_pitch + region_pixel_left * bytes_per_pixel;
+ uint8_t *dest = framebuffer_address + (region_pixel_y + row) * framebuffer_pitch + region_pixel_left * bytes_per_pixel;
+ memmove(dest, src, row_bytes);
+ }
+
+ // Clear the last line of the region
+ uint16_t clear_start_y = region_pixel_y + region_pixel_height - line_height;
+ for (uint16_t row = 0; row < line_height; row++) {
+ auto row_add = (uint32_t *) (framebuffer_address + (clear_start_y + row) * framebuffer_pitch + region_pixel_left * 4);
+ for (uint16_t col = 0; col < region_pixel_width; col++) {
+ row_add[col] = fill_value;
+ }
+ }
+
+ //Update any per-pixel colour metadata
+ uint16_t text_row = top + height - 1;
+ for (uint16_t x = left; x < left + width; x++) {
+ set_foreground_color(x, text_row, to_set_foreground);
+ set_background_color(x, text_row, to_set_background);
+ }
}
/**
@@ -339,27 +331,27 @@ void VESABootConsole::scroll_up(uint16_t left, uint16_t top, uint16_t width,
*/
void VESABootConsole::print_logo_kernel_panic() {
- // Load the logo
- const char* logo = header_data_kp;
+ // Load the logo
+ const char *logo = header_data_kp;
- // Find the bottom right of the screen
- uint32_t right_x = s_graphics_context->width() - kp_width - 10;
- uint32_t bottom_y = s_graphics_context->height() - kp_height - 10;
+ // Find the bottom right of the screen
+ uint32_t right_x = s_graphics_context->width() - kp_width - 10;
+ uint32_t bottom_y = s_graphics_context->height() - kp_height - 10;
- // Draw the logo
- for (uint32_t logoY = 0; logoY < kp_height; ++logoY) {
- for (uint32_t logoX = 0; logoX < kp_width; ++logoX) {
+ // Draw the logo
+ for (uint32_t logoY = 0; logoY < kp_height; ++logoY) {
+ for (uint32_t logoX = 0; logoX < kp_width; ++logoX) {
- // Store the pixel in the logo
- uint8_t pixel[3] = {0};
+ // Store the pixel in the logo
+ uint8_t pixel[3] = {0};
- // Get the pixel from the logo
- LOGO_HEADER_PIXEL(logo, pixel)
+ // Get the pixel from the logo
+ LOGO_HEADER_PIXEL(logo, pixel)
- // Draw the pixel
- s_graphics_context->put_pixel(right_x + logoX, bottom_y + logoY, common::Colour(pixel[0], pixel[1], pixel[2]));
- }
- }
+ // Draw the pixel
+ s_graphics_context->put_pixel(right_x + logoX, bottom_y + logoY, common::Colour(pixel[0], pixel[1], pixel[2]));
+ }
+ }
}
@@ -368,15 +360,14 @@ void VESABootConsole::print_logo_kernel_panic() {
*/
void VESABootConsole::finish() {
- // Done
- Logger::INFO() << "MaxOS Kernel Successfully Booted\n";
-
- // Move COUT to the bottom of the screen
- cout->set_cursor(width(), height());
+ // Done
+ Logger::HEADER() << "MaxOS Kernel Successfully Booted\n";
- // Disable the logger
- Logger::active_logger()->disable_log_writer(cout);
+ // CPU::PANIC will override a disabled logger so the console should scroll itself into view as it is unknown what
+ // will be on the screen now and that may mess with the presentation of the text (ie white text on a white background)
+ cout->set_cursor(width(), height());
+ Logger::active_logger()->disable_log_writer(cout);
}
/**
@@ -386,48 +377,45 @@ void VESABootConsole::finish() {
*/
void VESABootConsole::update_progress_bar(uint8_t percentage) {
- // Must be within bounds
- if(percentage > 100)
- percentage = 100;
+ // Check bounds
+ if (percentage > 100)
+ percentage = 100;
- // Must have a valid graphics context
- if(s_graphics_context == nullptr)
- return;
+ // Must have a valid graphics context
+ if (s_graphics_context == nullptr)
+ return;
- uint8_t progress_height = 15;
- uint8_t progress_spacing = 20;
- uint8_t progress_width_cull = 40;
+ uint8_t progress_height = 15;
+ uint8_t progress_spacing = 20;
+ uint8_t progress_width_cull = 40;
- // Find the center of the screen
- uint32_t right_x = (s_graphics_context->width()/2) - logo_width / 2;
- uint32_t bottom_y = (s_graphics_context->height()/2 - 80) - logo_height / 2;
+ // Find the center of the screen
+ uint32_t right_x = (s_graphics_context->width() / 2) - logo_width / 2;
+ uint32_t bottom_y = (s_graphics_context->height() / 2 - 80) - logo_height / 2;
- // Find the bounds
- uint32_t start_x = progress_width_cull;
- uint32_t start_y = logo_height + progress_spacing;
- uint32_t end_x = logo_width - progress_width_cull;
- uint32_t end_y = logo_height + progress_height + progress_spacing;
+ // Find the bounds
+ uint32_t start_x = progress_width_cull;
+ uint32_t start_y = logo_height + progress_spacing;
+ uint32_t end_x = logo_width - progress_width_cull;
+ uint32_t end_y = logo_height + progress_height + progress_spacing;
- // Draw the progress bar
- for (uint32_t progress_y = start_y; progress_y < end_y; ++progress_y) {
- for (uint32_t progress_x = start_x; progress_x < end_x; ++progress_x) {
+ // Draw the progress bar
+ for (uint32_t progress_y = start_y; progress_y < end_y; ++progress_y) {
+ for (uint32_t progress_x = start_x; progress_x < end_x; ++progress_x) {
- // Check if drawing border
- bool is_border = (progress_y == start_y) || (progress_y == end_y - 1) ||
- (progress_x == start_x) || (progress_x == end_x - 1);
+ // Check if drawing border
+ bool is_border = (progress_y == start_y) || (progress_y == end_y - 1) ||
+ (progress_x == start_x) || (progress_x == end_x - 1);
- // Only draw the border if it is the first time drawing it
- is_border = is_border && percentage == 0;
+ // Only draw the border if it is the first time drawing it
+ is_border = is_border && percentage == 0;
- // If it is not within the percentage, skip it
- if (progress_x > logo_width * percentage / 100 && !is_border)
- continue;
+ // If it is not within the percentage, skip it
+ if (progress_x > logo_width * percentage / 100 && !is_border)
+ continue;
+ s_graphics_context->put_pixel(right_x + progress_x, bottom_y + progress_y, Colour(0xFF, 0xFF, 0xFF));
- // Draw the pixel
- s_graphics_context->put_pixel(right_x + progress_x, bottom_y + progress_y, Colour(0xFF, 0xFF, 0xFF));
-
- }
- }
-
-}
+ }
+ }
+}
\ No newline at end of file
diff --git a/kernel/src/drivers/disk/ata.cpp b/kernel/src/drivers/disk/ata.cpp
new file mode 100644
index 00000000..9365bcb3
--- /dev/null
+++ b/kernel/src/drivers/disk/ata.cpp
@@ -0,0 +1,247 @@
+//
+// Created by 98max on 24/10/2022.
+//
+
+#include
+
+using namespace MaxOS;
+using namespace MaxOS::common;
+using namespace MaxOS::hardwarecommunication;
+using namespace MaxOS::drivers;
+using namespace MaxOS::drivers::disk;
+
+AdvancedTechnologyAttachment::AdvancedTechnologyAttachment(uint16_t port_base, bool master)
+: m_data_port(port_base),
+ m_error_port(port_base + 1),
+ m_sector_count_port(port_base + 2),
+ m_LBA_low_port(port_base + 3),
+ m_LBA_mid_port(port_base + 4),
+ m_LBA_high_Port(port_base + 5),
+ m_device_port(port_base + 6),
+ m_command_port(port_base + 7),
+ m_control_port(port_base + 0x206),
+ m_is_master(master)
+{
+
+}
+
+AdvancedTechnologyAttachment::~AdvancedTechnologyAttachment() = default;
+
+/**
+ * @brief Identify the ATA device
+ *
+ * @return True if the device is present, false otherwise
+ */
+bool AdvancedTechnologyAttachment::identify() {
+
+ // Select the device (master or slave)
+ m_device_port.write(m_is_master ? 0xA0 : 0xB0);
+
+ // Reset the High Order Byte
+ m_control_port.write(0);
+
+ // Check if the master is present
+ m_device_port.write(0xA0);
+ uint8_t status = m_command_port.read();
+ if (status == 0xFF) {
+ Logger::WARNING() << "ATA Device: Invalid status";
+ return false;
+ }
+
+ // Select the device (master or slave)
+ m_device_port.write(m_is_master ? 0xA0 : 0xB0);
+
+ // Clear the ports
+ m_sector_count_port.write(0);
+ m_LBA_low_port.write(0);
+ m_LBA_mid_port.write(0);
+ m_LBA_high_Port.write(0);
+
+ // Check if the device is present
+ m_command_port.write(0x0EC);
+ status = m_command_port.read();
+ if (status == 0x00)
+ return false;
+
+ // Wait for the device to be ready or for an error to occur
+ while (((status & 0x80) == 0x80) && ((status & 0x01) != 0x01))
+ status = m_command_port.read();
+
+ //Check for any errors
+ if (status & 0x01) {
+ Logger::WARNING() << "ATA Device: Error reading status\n";
+ return false;
+ }
+
+ // Read the rest of the data as a whole sector needs to be read
+ for (uint16_t i = 0; i < 256; ++i)
+ uint16_t data = m_data_port.read();
+
+ // Device is present and ready
+ return true;
+}
+
+/**
+ * @brief Read a sector from the ATA device
+ *
+ * @param sector The sector to read
+ * @param data_buffer The data to read into
+ * @param amount The amount of bytes to read from that sector
+ */
+void AdvancedTechnologyAttachment::read(uint32_t sector, buffer_t *data_buffer, size_t amount) {
+
+ // Don't allow reading more than a sector
+ if (sector & 0xF0000000 || amount > m_bytes_per_sector)
+ return;
+
+ // Select the device (master or slave)
+ m_device_port.write((m_is_master ? 0xE0 : 0xF0) | ((sector & 0x0F000000) >> 24));
+
+ // Device is busy (TODO: YIELD)
+ while ((m_command_port.read() & 0x80) != 0);
+
+ // Reset the device
+ m_error_port.write(0);
+ m_sector_count_port.write(1);
+
+ // Split the sector into the ports
+ m_LBA_low_port.write(sector & 0x000000FF);
+ m_LBA_mid_port.write((sector & 0x0000FF00) >> 8);
+ m_LBA_high_Port.write((sector & 0x00FF0000) >> 16);
+
+ // Tell the device to prepare for reading
+ m_command_port.write(0x20);
+
+ // Make sure the device is there
+ uint8_t status = m_command_port.read();
+ if (status == 0x00)
+ return;
+
+ // Wait for the device to be ready or for an error to occur TODO: Userspace block here
+ while (((status & 0x80) == 0x80) && ((status & 0x01) != 0x01))
+ status = m_command_port.read();
+
+ //Check for any errors
+ if (status & 0x01)
+ return;
+
+ for (size_t i = 0; i < amount; i += 2) {
+
+ // Read from the disk (2 bytes) and store the first byte
+ uint16_t read_data = m_data_port.read();
+ data_buffer->write(read_data & 0x00FF);
+
+ // Place the second byte in the array if there is one
+ if (i + 1 < amount)
+ data_buffer->write((read_data >> 8) & 0x00FF);
+ }
+
+ // Read the remaining bytes as a full sector has to be read
+ for (uint16_t i = amount + (amount % 2); i < m_bytes_per_sector; i += 2)
+ m_data_port.read();
+}
+
+/**
+ * @brief write to a sector on the ATA device
+ *
+ * @param sector The sector to write to
+ * @param data The data to write
+ * @param count The amount of data to write to that sector
+ */
+void AdvancedTechnologyAttachment::write(uint32_t sector, const buffer_t *data, size_t count) {
+
+ // Don't allow writing more than a sector
+ if (sector > 0x0FFFFFFF || count > m_bytes_per_sector)
+ return;
+
+ // Select the device (master or slave)
+ m_device_port.write(m_is_master ? 0xE0 : 0xF0 | ((sector & 0x0F000000) >> 24));
+
+ // Device is busy (TODO: YIELD)
+ while ((m_command_port.read() & 0x80) != 0);
+
+ // Reset the device
+ m_error_port.write(0);
+ m_sector_count_port.write(1);
+
+ // Split the sector into the ports
+ m_LBA_low_port.write(sector & 0x000000FF);
+ m_LBA_mid_port.write((sector & 0x0000FF00) >> 8);
+ m_LBA_high_Port.write((sector & 0x00FF0000) >> 16);
+
+ // Send the write command
+ m_command_port.write(0x30);
+
+ // Wait for the device be ready writing (TODO: YIELD)
+ uint8_t status = m_command_port.read();
+ while ((status & 0x80) != 0 || (status & 0x08) == 0)
+ status = m_command_port.read();
+
+ // Write the data to the device
+ for (uint16_t i = 0; i < m_bytes_per_sector; i += 2) {
+
+ uint16_t writeData = data->read();
+
+ // Place the next byte in the array if there is one
+ if (i + 1 < count)
+ writeData |= (uint16_t) (data->read()) << 8;
+
+ m_data_port.write(writeData);
+ }
+
+ // Write the remaining bytes as a full sector has to be written
+ for (int i = count + (count % 2); i < m_bytes_per_sector; i += 2)
+ m_data_port.write(0x0000);
+
+ // Wait for the device to finish writing (TODO: YIELD)
+ status = m_command_port.read();
+ while ((status & 0x80) != 0 || (status & 0x08) != 0)
+ status = m_command_port.read();
+
+ flush();
+}
+
+/**
+ * @brief Flush the cache of the ATA device
+ */
+void AdvancedTechnologyAttachment::flush() {
+
+ // Select the device (master or slave)
+ m_device_port.write(m_is_master ? 0xE0 : 0xF0);
+
+ // Send the flush command
+ m_command_port.write(0xE7);
+
+ // Make sure the device is there
+ uint8_t status = m_command_port.read();
+ if (status == 0x00)
+ return;
+
+ // Wait for the device to be ready or for an error to occur
+ while (((status & 0x80) == 0x80) && ((status & 0x01) != 0x01))
+ status = m_command_port.read();
+
+ // Check for an error
+ if (status & 0x01)
+ return;
+
+ // ...
+}
+
+/**
+ * @brief Get the device name
+ *
+ * @return The name of the device
+ */
+string AdvancedTechnologyAttachment::device_name() {
+ return "Advanced Technology Attachment";
+}
+
+/**
+ * @brief Get the vendor name
+ *
+ * @return The name of the vendor
+ */
+string AdvancedTechnologyAttachment::vendor_name() {
+ return "IDE";
+}
diff --git a/kernel/src/drivers/disk/disk.cpp b/kernel/src/drivers/disk/disk.cpp
new file mode 100644
index 00000000..ed97099a
--- /dev/null
+++ b/kernel/src/drivers/disk/disk.cpp
@@ -0,0 +1,88 @@
+//
+// Created by Max Tyson on 18/04/2025.
+//
+
+#include
+
+using namespace MaxOS;
+using namespace MaxOS::common;
+using namespace MaxOS::drivers;
+using namespace MaxOS::drivers::disk;
+
+Disk::Disk() = default;
+
+Disk::~Disk() = default;
+
+/**
+ * @brief Read data from the disk into a buffer (max capacity 512 bytes)
+ *
+ * @param sector The sector to read from
+ * @param data_buffer The buffer to read the data into
+ */
+void Disk::read(uint32_t sector, common::buffer_t* data_buffer) {
+
+ size_t amount = (data_buffer->capacity() > 512) ? 512 : data_buffer->capacity();
+ read(sector, data_buffer, amount);
+
+}
+
+/**
+ * @brief Read data from the disk
+ *
+ * @param sector The sector to read from
+ * @param data_buffer The buffer to read the data into
+ * @param amount The amount of data to read
+ */
+void Disk::read(uint32_t sector, buffer_t *data_buffer, size_t amount) {
+
+}
+
+void Disk::write(uint32_t sector, common::buffer_t const *data) {
+
+ size_t amount = (data->capacity() > 512) ? 512 : data->capacity();
+ write(sector, data, amount);
+
+}
+
+/**
+ * @brief Write data to the disk
+ *
+ * @param sector The sector to write to
+ * @param data_buffer The buffer to write the data into
+ * @param amount The amount of data to write
+ */
+void Disk::write(uint32_t sector, const buffer_t *data, size_t count) {
+}
+
+/**
+ * @brief Flush the disk cache
+ *
+ * This function is used to flush the disk cache to ensure that all data is written to the disk.
+ */
+void Disk::flush() {
+}
+
+/**
+ * @brief Activate the disk driver
+ */
+void Disk::activate() {
+ Driver::activate();
+}
+
+/**
+ * @brief Get the device name
+ *
+ * @return The name of the device
+ */
+string Disk::device_name() {
+ return "Disk";
+}
+
+/**
+ * @brief Get the vendor name
+ *
+ * @return The name of the vendor
+ */
+string Disk::vendor_name() {
+ return "Generic";
+}
\ No newline at end of file
diff --git a/kernel/src/drivers/disk/disk/ata.cpp b/kernel/src/drivers/disk/disk/ata.cpp
deleted file mode 100644
index 768dadc0..00000000
--- a/kernel/src/drivers/disk/disk/ata.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-//
-// Created by 98max on 24/10/2022.
-//
-
-#include
-
-using namespace MaxOS;
-using namespace MaxOS::common;
-using namespace MaxOS::hardwarecommunication;
-using namespace MaxOS::drivers;
-using namespace MaxOS::drivers::disk;
-
-AdvancedTechnologyAttachment::AdvancedTechnologyAttachment(uint16_t port_base, bool master, OutputStream*output_stream)
-: Driver(output_stream),
- m_data_port(port_base),
- m_error_port(port_base + 1),
- m_sector_count_port(port_base + 2),
- m_LBA_low_port(port_base + 3),
- m_LBA_mid_port(port_base + 4),
- m_LBA_high_Port(port_base + 5),
- m_device_port(port_base + 6),
- m_command_port(port_base + 7),
- m_control_port(port_base + 0x206),
- m_is_master(master),
- ata_message_stream(output_stream)
-{
-
-}
-
-AdvancedTechnologyAttachment::~AdvancedTechnologyAttachment() = default;
-
-/**
- * @brief Identify the ATA device
- */
-void AdvancedTechnologyAttachment::identify() {
-
- // Select the device (master or slave)
- m_device_port.write(m_is_master ? 0xA0 : 0xB0);
-
- // Reset the HOB (High Order Byte)
- m_control_port.write(0);
-
- // Check if the master is present
- m_device_port.write(0xA0);
- uint8_t status = m_command_port.read();
- if(status == 0xFF){
- ata_message_stream-> write("Invalid Status");
- return;
- }
-
- // Select the device (master or slave)
- m_device_port.write(m_is_master ? 0xA0 : 0xB0);
-
- // Clear the ports
- m_sector_count_port.write(0);
- m_LBA_low_port.write(0);
- m_LBA_mid_port.write(0);
- m_LBA_high_Port.write(0);
-
- // Send the identify command
- m_command_port.write(0x0EC);
-
- // Check if the device is present
- status = m_command_port.read();
- if(status == 0x00)
- return;
-
- // Wait for the device to be ready or for an error to occur
- while (((status & 0x80) == 0x80) && ((status & 0x01) != 0x01))
- status = m_command_port.read();
-
- //Check for any errors
- if(status & 0x01){
- ata_message_stream-> write("ERROR");
- return;
- }
-
- // read the data and print it
- for (uint16_t i = 0; i < 256; ++i) {
- uint16_t data = m_data_port.read();
- ata_message_stream-> write(" 0x");
- ata_message_stream-> write_hex(data);
- }
-}
-
-/**
- * @brief read a sector from the ATA device
- *
- * @param sector The sector to read
- * @param data The data to read into
- * @param count The amount of data to read from that sector
- */
-void AdvancedTechnologyAttachment::read_28(uint32_t sector, uint8_t* data, int count)
-{
- // Don't allow reading more than a sector
- if(sector & 0xF0000000 || count > m_bytes_per_sector)
- return;
-
- // Select the device (master or slave) and reset it
- m_device_port.write((m_is_master ? 0xE0 : 0xF0) |
- ((sector & 0x0F000000) >> 24));
- m_error_port.write(0);
- m_sector_count_port.write(1);
-
- // Split the sector into the ports
- m_LBA_low_port.write(sector & 0x000000FF);
- m_LBA_mid_port.write((sector & 0x0000FF00) >> 8);
- m_LBA_high_Port.write((sector & 0x00FF0000) >> 16);
-
- // Send the read command
- m_command_port.write(0x20);
-
- // Make sure the device is there
- uint8_t status = m_command_port.read();
- if(status == 0x00)
- return;
-
- // Wait for the device to be ready or for an error to occur
- while(((status & 0x80) == 0x80) && ((status & 0x01) != 0x01))
- status = m_command_port.read();
-
- //Check for any errors
- if(status & 0x01)
- return;
-
- // read the data and store it in the array
- for(int i = 0; i < count; i+= 2)
- {
- uint16_t read_data = m_data_port.read();
-
- data[i] = read_data & 0x00FF;
-
- // Place the next byte in the array if there is one
- if(i+1 < count)
- data[i+1] = (read_data >> 8) & 0x00FF;
- }
-
- // read the remaining bytes
- for(uint16_t i = count + (count % 2); i < m_bytes_per_sector; i+= 2)
- m_data_port.read();
-}
-
-/**
- * @brief write to a sector on the ATA device
- *
- * @param sector The sector to write to
- * @param count The amount of data to write to that sector
- */
-void AdvancedTechnologyAttachment::write_28(uint32_t sector, const uint8_t* data, int count){
-
- // Don't allow writing more han a sector
- if(sector > 0x0FFFFFFF || count > m_bytes_per_sector)
- return;
-
- // Select the device (master or slave) and reset it
- m_device_port.write(m_is_master ? 0xE0
- : 0xF0 | ((sector & 0x0F000000) >> 24));
- m_error_port.write(0);
- m_sector_count_port.write(1);
-
- // Split the sector into the ports
- m_LBA_low_port.write(sector & 0x000000FF);
- m_LBA_mid_port.write((sector & 0x0000FF00) >> 8);
- m_LBA_high_Port.write((sector & 0x00FF0000) >> 16);
-
- // Send the write command
- m_command_port.write(0x30);
-
- // write the data to the device
- for (uint16_t i = 0; i < m_bytes_per_sector; i+= 2) {
-
- uint16_t writeData = data[i];
-
- // Place the next byte in the array if there is one
- if(i+1 < count)
- writeData |= ((uint16_t)data[i+1]) << 8;
-
- m_data_port.write(writeData);
- }
-
- // write the remaining bytes
- for(int i = count + (count%2); i < m_bytes_per_sector; i += 2)
- m_data_port.write(0x0000);
-}
-/**
- * @brief Flush the cache of the ATA device
- */
-void AdvancedTechnologyAttachment::flush() {
-
- // Select the device (master or slave)
- m_device_port.write(m_is_master ? 0xE0 : 0xF0);
-
- // Send the flush command
- m_command_port.write(0xE7);
-
- // Make sure the device is there
- uint8_t status = m_command_port.read();
- if(status == 0x00)
- return;
-
-
- // Wait for the device to be ready or for an error to occur
- while (((status & 0x80) == 0x80) && ((status & 0x01) != 0x01))
- status = m_command_port.read();
-
- if(status & 0x01)
- return;
-
-}
-
-/**
- * @brief Activate the ATA device
- */
-void AdvancedTechnologyAttachment::activate() {
- Driver::activate();
-}
-
-/**
- * @brief Get the device name
- *
- * @return The name of the device
- */
-string AdvancedTechnologyAttachment::device_name() {
-
- return "Advanced Technology Attachment";
-
-}
-
-/**
- * @brief Get the vendor name
- *
- * @return The name of the vendor
- */
-string AdvancedTechnologyAttachment::vendor_name() {
-
- return "IDE";
-}
diff --git a/kernel/src/drivers/disk/ide.cpp b/kernel/src/drivers/disk/ide.cpp
new file mode 100644
index 00000000..404ee9be
--- /dev/null
+++ b/kernel/src/drivers/disk/ide.cpp
@@ -0,0 +1,94 @@
+//
+// Created by Max Tyson on 18/04/2025.
+//
+#include
+
+
+using namespace MaxOS;
+using namespace MaxOS::hardwarecommunication;
+using namespace MaxOS::drivers;
+using namespace MaxOS::drivers::disk;
+using namespace MaxOS::filesystem;
+using namespace MaxOS::filesystem::partition;
+
+IntegratedDriveElectronicsController::IntegratedDriveElectronicsController(
+PeripheralComponentInterconnectDeviceDescriptor *device_descriptor)
+{
+ // TODO: Use the device descriptor to get the port base and add the devices dynamically
+
+ // Primary
+ auto primary_maser = new AdvancedTechnologyAttachment(0x1F0, true);
+ auto primary_slave = new AdvancedTechnologyAttachment(0x1F0, false);
+ devices.insert(primary_maser, true);
+ devices.insert(primary_slave, false);
+
+ // Secondary
+ auto secondary_maser = new AdvancedTechnologyAttachment(0x170, true);
+ auto secondary_slave = new AdvancedTechnologyAttachment(0x170, false);
+ devices.insert(secondary_maser, true);
+ devices.insert(secondary_slave, false);
+
+}
+
+IntegratedDriveElectronicsController::~IntegratedDriveElectronicsController() = default;
+
+/**
+ * @brief Initialise the IDE controller by identifying the devices
+ */
+void IntegratedDriveElectronicsController::initialise() {
+
+ // Loop through the devices and identify them
+ for (auto &device: devices) {
+
+ // Check if the device is present
+ auto ata_device = device.first;
+ if (ata_device == nullptr)
+ continue;
+
+ // Identify the device
+ bool exists = ata_device->identify();
+
+ // Remove the device if it does not exist
+ if (!exists) {
+ devices.erase(ata_device);
+ delete ata_device;
+ continue;
+ }
+ }
+
+ // Log the init done
+ Logger::DEBUG() << "IDE Controller: Initialised " << devices.size() << " devices\n";
+}
+
+/**
+ * @brief Activate the IDE controller by mounting the devices to the virtual file system
+ */
+void IntegratedDriveElectronicsController::activate() {
+
+ // Loop through the devices and load the partitions
+ for (auto &device: devices) {
+
+ // Ensure there is a device and that it is the master
+ if (device.first == nullptr || !device.second)
+ continue;
+
+ // Mount the device
+ MSDOSPartition::mount_partitions(device.first);
+
+ }
+}
+
+
+/**
+ * @brief Get the vendor name
+ */
+string IntegratedDriveElectronicsController::vendor_name() {
+ return "Intel";
+}
+
+/**
+ * @brief Get the device name
+ */
+string IntegratedDriveElectronicsController::device_name() {
+ return "PIIX4";
+}
\ No newline at end of file
diff --git a/kernel/src/drivers/driver.cpp b/kernel/src/drivers/driver.cpp
index 0a9c2261..619054a1 100644
--- a/kernel/src/drivers/driver.cpp
+++ b/kernel/src/drivers/driver.cpp
@@ -4,32 +4,28 @@
#include
#include
+
using namespace MaxOS;
using namespace MaxOS::common;
using namespace MaxOS::drivers;
using namespace MaxOS::memory;
using namespace MaxOS::hardwarecommunication;
-Driver::Driver(OutputStream* driverMessageStream)
-: m_driver_message_stream(driverMessageStream) {
+Driver::Driver() = default;
-}
-
-Driver::~Driver(){
- this ->m_driver_message_stream = nullptr;
-}
+Driver::~Driver() = default;
/**
* @brief activate the driver
*/
-void Driver::activate(){
+void Driver::activate() {
}
/**
* @brief deactivate the driver
*/
-void Driver::deactivate(){
+void Driver::deactivate() {
}
@@ -45,70 +41,17 @@ void Driver::initialise() {
*
* @return How long in milliseconds it took to reset the driver
*/
-uint32_t Driver::reset(){
- return 0;
+uint32_t Driver::reset() {
+ return 0;
}
/**
- * @brief write a message to the driver message stream if it is not null
- *
- * @param message The message to write
- */
-void Driver::error_message(const string& message) const {
-
- // If there is a driver message stream write the message to it
- if(m_driver_message_stream != nullptr)
- m_driver_message_stream-> write(message);
-
-}
-
-/**
- * @brief write a character to the driver message stream if it is not null
- *
- * @param char_to_write The character to write
- */
-void Driver::error_message(char char_to_write) const {
-
- // If there is a driver message stream write the character to it
- if(m_driver_message_stream != nullptr)
- m_driver_message_stream-> write_char(char_to_write);
-
-}
-
-
-/**
- * @brief write an integer to the driver message stream if it is not null
- *
- * @param int_to_write The integer to write
- */
-void Driver::error_message(int int_to_write) const {
-
- // If there is a driver message stream write the integer to it
- if(m_driver_message_stream != nullptr)
- m_driver_message_stream-> write_int(int_to_write);
-}
-
-/**
- * @brief write a hex to the driver message stream if it is not null
- *
- * @param hex_to_write The hex to write
- */
-void Driver::error_message(uint32_t hex_to_write) const {
-
- // If there is a driver message stream write the hex to it
- if(m_driver_message_stream != nullptr)
- m_driver_message_stream->write_hex(hex_to_write);
-
-}
-
-/**
- * @brief Get the vendor name of the driver
+ * @brief Get who created the device
*
* @return The vendor name of the driver
*/
-string Driver::vendor_name()
-{
- return "Generic";
+string Driver::vendor_name() {
+ return "Generic";
}
/**
@@ -116,57 +59,49 @@ string Driver::vendor_name()
*
* @return The device name of the driver
*/
-string Driver::device_name()
-{
- return "Unknown Driver";
+string Driver::device_name() {
+ return "Unknown Driver";
}
-DriverSelectorEventHandler::DriverSelectorEventHandler()
-= default;
+DriverSelectorEventHandler::DriverSelectorEventHandler() = default;
-DriverSelectorEventHandler::~DriverSelectorEventHandler()
-= default;
+DriverSelectorEventHandler::~DriverSelectorEventHandler() = default;
/**
* @brief This function is called when a driver is selected
*
* @param driver The driver that was selected
*/
-void DriverSelectorEventHandler::on_driver_selected(Driver*)
-{
+void DriverSelectorEventHandler::on_driver_selected(Driver *) {
}
-DriverSelector::DriverSelector()
-= default;
+DriverSelector::DriverSelector() = default;
-DriverSelector::~DriverSelector()
-= default;
+DriverSelector::~DriverSelector() = default;
/**
* @brief Select the drivers
*/
-void DriverSelector::select_drivers(DriverSelectorEventHandler*)
-{
+void DriverSelector::select_drivers(DriverSelectorEventHandler *) {
}
-DriverManager::DriverManager()
-{
+DriverManager::DriverManager() {
- Logger::INFO() << "Setting up Driver Manager \n";
- add_driver_selector(new PeripheralComponentInterconnectController);
- // add_driver_selector(new UniversalSerialBusController);
+ Logger::INFO() << "Setting up Driver Manager \n";
+ add_driver_selector(new PeripheralComponentInterconnectController);
+ // add_driver_selector(new UniversalSerialBusController);
}
DriverManager::~DriverManager() {
- // Remove any drivers that are still attached
- while (!m_drivers.empty())
- remove_driver(*m_drivers.begin());
+ // Remove any drivers that are still attached
+ while (!m_drivers.empty())
+ remove_driver(*m_drivers.begin());
- // Free the driver selectors
- for(auto & driver_selector : m_driver_selectors)
- delete driver_selector;
+ // Free the driver selectors
+ for (auto &driver_selector: m_driver_selectors)
+ delete driver_selector;
}
@@ -175,8 +110,8 @@ DriverManager::~DriverManager() {
*
* @param driver The driver to add
*/
-void DriverManager::add_driver(Driver* driver){
- m_drivers.push_back(driver);
+void DriverManager::add_driver(Driver *driver) {
+ m_drivers.push_back(driver);
}
/**
@@ -184,40 +119,35 @@ void DriverManager::add_driver(Driver* driver){
*
* @param driver The driver to remove
*/
-void DriverManager::remove_driver(Driver* driver) {
-
- // deactivate the driver
- driver -> deactivate();
+void DriverManager::remove_driver(Driver *driver) {
- // Remove the driver
- m_drivers.erase(driver);
+ driver->deactivate();
+ m_drivers.erase(driver);
}
/**
* @brief When a driver is selected add it to the manager
*/
-void DriverManager::on_driver_selected(Driver* driver) {
- add_driver(driver);
+void DriverManager::on_driver_selected(Driver *driver) {
+ add_driver(driver);
}
/**
* @brief Add a driver selector to the manager
*/
-void DriverManager::add_driver_selector(DriverSelector* driver_selector) {
+void DriverManager::add_driver_selector(DriverSelector *driver_selector) {
- // Add the driver selector
- m_driver_selectors.push_back(driver_selector);
+ m_driver_selectors.push_back(driver_selector);
}
/**
* @brief Remove a driver selector from the manager
*/
-void DriverManager::remove_driver_selector(DriverSelector* driver_selector) {
+void DriverManager::remove_driver_selector(DriverSelector *driver_selector) {
- // Remove the driver selector
- m_driver_selectors.erase(driver_selector);
+ m_driver_selectors.erase(driver_selector);
}
@@ -226,11 +156,11 @@ void DriverManager::remove_driver_selector(DriverSelector* driver_selector) {
*/
void DriverManager::find_drivers() {
- Logger::INFO() << "Finding Drivers \n";
+ Logger::INFO() << "Finding Drivers \n";
- // Select the drivers
- for(auto & driver_selector : m_driver_selectors)
- driver_selector -> select_drivers(this);
+ // Select the drivers
+ for (auto &driver_selector: m_driver_selectors)
+ driver_selector->select_drivers(this);
}
/**
@@ -240,20 +170,19 @@ void DriverManager::find_drivers() {
*/
uint32_t DriverManager::reset_devices() {
- Logger::INFO() << "Resetting Devices \n";
+ Logger::INFO() << "Resetting Devices \n";
- uint32_t resetWaitTime = 0;
- for(auto & driver : m_drivers)
- {
- // Reset the driver
- uint32_t waitTime = driver->reset();
+ uint32_t resetWaitTime = 0;
+ for (auto &driver: m_drivers) {
+ // Reset the driver
+ uint32_t waitTime = driver->reset();
- // If the wait time is longer than the current longest wait time, set it as the new longest wait time
- if(waitTime > resetWaitTime)
- resetWaitTime = waitTime;
- }
+ // If the wait time is longer than the current longest wait time, set it as the new longest wait time
+ if (waitTime > resetWaitTime)
+ resetWaitTime = waitTime;
+ }
- return resetWaitTime;
+ return resetWaitTime;
}
/**
@@ -261,11 +190,11 @@ uint32_t DriverManager::reset_devices() {
*/
void DriverManager::initialise_drivers() {
- Logger::INFO() << "Initialising Drivers \n";
+ Logger::INFO() << "Initialising Drivers \n";
- // Initialise the drivers
- for(auto& driver : m_drivers)
- driver->initialise();
+ // Initialise the drivers
+ for (auto &driver: m_drivers)
+ driver->initialise();
}
@@ -274,9 +203,9 @@ void DriverManager::initialise_drivers() {
*/
void DriverManager::deactivate_drivers() {
- // Deactivate the drivers
- for(auto & driver : m_drivers)
- driver->deactivate();
+ // Deactivate the drivers
+ for (auto &driver: m_drivers)
+ driver->deactivate();
}
@@ -286,10 +215,10 @@ void DriverManager::deactivate_drivers() {
void DriverManager::activate_drivers() {
- Logger::INFO() << "Activating Drivers \n";
+ Logger::INFO() << "Activating Drivers \n";
- // Activate the drivers
- for(auto & driver : m_drivers)
- driver->activate();
+ // Activate the drivers
+ for (auto &driver: m_drivers)
+ driver->activate();
}
diff --git a/kernel/src/drivers/ethernet/amd_am79c973.cpp b/kernel/src/drivers/ethernet/amd_am79c973.cpp
index 578b2327..01962c7c 100644
--- a/kernel/src/drivers/ethernet/amd_am79c973.cpp
+++ b/kernel/src/drivers/ethernet/amd_am79c973.cpp
@@ -11,9 +11,12 @@ using namespace MaxOS::drivers;
using namespace MaxOS::drivers::ethernet;
using namespace MaxOS::hardwarecommunication;
-AMD_AM79C973::AMD_AM79C973(PeripheralComponentInterconnectDeviceDescriptor *dev, OutputStream *amdNetMessageStream)
-: EthernetDriver(amdNetMessageStream),
- InterruptHandler(0x20 + dev -> interrupt),
+/// MAX OS NET CODE:
+/// All the old (this) networking code poorly written and not used, this will be moved to userspace in the future
+/// but is kept here as a reference for now.
+
+AMD_AM79C973::AMD_AM79C973(PeripheralComponentInterconnectDeviceDescriptor *dev)
+: InterruptHandler(0x20 + dev -> interrupt),
MACAddress0Port(dev ->port_base),
MACAddress2Port(dev ->port_base + 0x02),
MACAddress4Port(dev ->port_base + 0x04),
@@ -169,13 +172,13 @@ void AMD_AM79C973::handle_interrupt() {
// Errors
if((temp & 0x8000) == 0x8000)
- error_message("AMD am79c973 ERROR: ");
+ Logger::WARNING() << "AMD am79c973 ERROR: ";
if((temp & 0x2000) == 0x2000)
- error_message("COLLISION ERROR\n");
+ Logger::WARNING() << "COLLISION ERROR\n";
if((temp & 0x1000) == 0x1000)
- error_message("MISSED FRAME\n");
+ Logger::WARNING() << "MISSED FRAME\n";
if((temp & 0x0800) == 0x0800)
- error_message("MEMORY ERROR\n");
+ Logger::WARNING() << "MEMORY ERROR\n";
// Responses
diff --git a/kernel/src/drivers/ethernet/ethernet.cpp b/kernel/src/drivers/ethernet/ethernet.cpp
index 0773fcff..7cfb102d 100644
--- a/kernel/src/drivers/ethernet/ethernet.cpp
+++ b/kernel/src/drivers/ethernet/ethernet.cpp
@@ -59,13 +59,8 @@ Event* EthernetDriverEventHandler::on_event(Event write("Sending: ");
-
- int displayType = 34; //What header to hide (Ethernet Header = 14, IP Header = 34, UDP = 42, TCP Header = 54, ARP = 42)
- for(uint32_t i = displayType; i < size; i++)
- {
- m_driver_message_stream->write_hex(buffer[i]);
- m_driver_message_stream-> write(" ");
- }
- m_driver_message_stream-> write("\n");
// Raise the event
raise_event(new BeforeSendEvent(buffer, size));
@@ -116,15 +102,6 @@ void EthernetDriver::DoSend(uint8_t*, uint32_t)
*/
void EthernetDriver::FireDataReceived(uint8_t* buffer, uint32_t size)
{
- m_driver_message_stream-> write("Receiving: ");
- //size = 64;
- int displayType = 34; //What header to hide (Ethernet Header = 14, IP Header = 34, UDP = 42, TCP Header = 54, ARP = 42)
- for(uint32_t i = displayType; i < size; i++)
- {
- m_driver_message_stream->write_hex(buffer[i]);
- m_driver_message_stream-> write(" ");
- }
- m_driver_message_stream-> write("\n");
// Raise the event
Vector*> values =
@@ -134,17 +111,14 @@ void EthernetDriver::FireDataReceived(uint8_t* buffer, uint32_t size)
for(auto & value : values) {
switch (value->type) {
case EthernetDriverEvents::DATA_RECEIVED:
- if(value->return_value.boolValue){
- m_driver_message_stream-> write("Sending back... \n");
+ if(value->return_value.boolValue)
Send(buffer, size);
- }
break;
default:
break;
}
}
- m_driver_message_stream-> write("DATA HANDLED\n");
}
/**
diff --git a/kernel/src/drivers/ethernet/intel_i217.cpp b/kernel/src/drivers/ethernet/intel_i217.cpp
index b295a26f..d9832764 100644
--- a/kernel/src/drivers/ethernet/intel_i217.cpp
+++ b/kernel/src/drivers/ethernet/intel_i217.cpp
@@ -11,6 +11,12 @@ using namespace MaxOS::drivers::ethernet;
using namespace MaxOS::hardwarecommunication;
using namespace memory;
+/// MAX OS NET CODE:
+/// All the old (this) networking code poorly written and not used, this will be moved to userspace in the future
+/// but is kept here as a reference for now.
+///
+/// See OSDEV wiki for the credit for this driver
+
// Buffer Sizes
#define buffer256 (3 << 16)
#define buffer512 (2 << 16)
@@ -23,8 +29,7 @@ using namespace memory;
///__DRIVER___
intel_i217::intel_i217(PeripheralComponentInterconnectDeviceDescriptor *deviceDescriptor)
-: EthernetDriver(nullptr),
- InterruptHandler(0x20 + deviceDescriptor->interrupt)
+: InterruptHandler(0x20 + deviceDescriptor->interrupt)
{
//Set the registers
@@ -63,13 +68,10 @@ intel_i217::intel_i217(PeripheralComponentInterconnectDeviceDescriptor *deviceDe
detectEEProm ();
if (readMACAddress()){
-
ownMAC = CreateMediaAccessControlAddress(macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]);
}else{
-
- error_message("ERROR, INIT FAILED, MAC ADDRESS NOT FOUND");
- while (true);
+ ASSERT(false, "ERROR, INIT FAILED, MAC ADDRESS NOT FOUND");
}
for(int i = 0; i < 0x80; i++) //Loop through all the registers
@@ -286,7 +288,6 @@ void intel_i217::sendInit() {
void intel_i217::activate() {
- m_driver_message_stream-> write("Activating Intel i217\n");
//Enable interrupts
Write(interruptMaskRegister ,0x1F6DC); //Enable all interrupts
@@ -300,7 +301,6 @@ void intel_i217::activate() {
sendInit();
active = true; // Set active to true
- m_driver_message_stream-> write("Intel i217 INIT DONE\n");
}
@@ -309,18 +309,17 @@ void intel_i217::handle_interrupt() {
Write(interruptMaskRegister, 0x1); //Clear the interrupt or it will hang
uint32_t temp = Read(0xc0); //read the interrupt status register
- m_driver_message_stream-> write("Interrupt from INTEL i217");
+ // if(temp & 0x04)
+ // m_driver_message_stream-> write("INTEL i217 START LINK");//initDone = true;
+ //
+ // if(temp & 0x10)
+ // m_driver_message_stream-> write("INTEL i217 GOOD THRESHOLD");
- if(temp & 0x04)
- m_driver_message_stream-> write("INTEL i217 START LINK");//initDone = true;
- if(temp & 0x10)
- m_driver_message_stream-> write("INTEL i217 GOOD THRESHOLD");
if(temp & 0x80) FetchDataReceived();
}
void intel_i217::FetchDataReceived() {
- m_driver_message_stream-> write("Fetching data... ");
uint16_t old_cur;
@@ -348,7 +347,6 @@ void intel_i217::FetchDataReceived() {
void intel_i217::DoSend(uint8_t* buffer, uint32_t size) {
- m_driver_message_stream-> write("Sending package... ");
while(!active);
//Put params into send buffer
@@ -369,12 +367,10 @@ void intel_i217::DoSend(uint8_t* buffer, uint32_t size) {
//Wait for the packet to be sent
while(!(sendDsrctrs[old_cur]->status & 0xff));
- m_driver_message_stream-> write(" Done\n");
}
uint64_t intel_i217::GetMediaAccessControlAddress() {
- m_driver_message_stream-> write("Getting MAC address... ");
while(ownMAC == 0);
return ownMAC;
diff --git a/kernel/src/drivers/peripherals/keyboard.cpp b/kernel/src/drivers/peripherals/keyboard.cpp
index d1b4ff78..8ff75780 100644
--- a/kernel/src/drivers/peripherals/keyboard.cpp
+++ b/kernel/src/drivers/peripherals/keyboard.cpp
@@ -4,18 +4,13 @@
#include
-
-
using namespace MaxOS;
using namespace MaxOS::common;
using namespace MaxOS::drivers;
using namespace MaxOS::drivers::peripherals;
using namespace MaxOS::hardwarecommunication;
-
-///___Handler___
-
-KeyboardEventHandler::KeyboardEventHandler()= default;
+KeyboardEventHandler::KeyboardEventHandler() = default;
KeyboardEventHandler::~KeyboardEventHandler() = default;
@@ -25,8 +20,7 @@ KeyboardEventHandler::~KeyboardEventHandler() = default;
* @param key_down_code The keycode of the key that was pressed
* @param key_down_state The state of the keyboard when the key was pressed
*/
-void KeyboardEventHandler::on_key_down(KeyCode, KeyboardState)
-{
+void KeyboardEventHandler::on_key_down(KeyCode, KeyboardState) {
}
/**
@@ -35,8 +29,7 @@ void KeyboardEventHandler::on_key_down(KeyCode, KeyboardState)
* @param key_up_code The keycode of the key that was released
* @param key_up_state The state of the keyboard when the key was released
*/
-void KeyboardEventHandler::on_key_up(KeyCode, KeyboardState)
-{
+void KeyboardEventHandler::on_key_up(KeyCode, KeyboardState) {
}
/**
@@ -45,31 +38,25 @@ void KeyboardEventHandler::on_key_up(KeyCode, KeyboardState)
* @param event The event to handle
* @return The event that was passed with the data modified
*/
-Event* KeyboardEventHandler::on_event(Event *event) {
+Event *KeyboardEventHandler::on_event(Event *event) {
- switch (event -> type) {
+ switch (event->type) {
- case KeyboardEvents::KEYDOWN:
- this->on_key_down(((KeyDownEvent *)event)->key_code,
- ((KeyDownEvent *)event)->keyboard_state);
- break;
+ case KeyboardEvents::KEYDOWN:
+ this->on_key_down(((KeyDownEvent *) event)->key_code, ((KeyDownEvent *) event)->keyboard_state);
+ break;
- case KeyboardEvents::KEYUP:
- this->on_key_up(((KeyUpEvent *)event)->key_code,
- ((KeyUpEvent *)event)->keyboard_state);
- break;
+ case KeyboardEvents::KEYUP:
+ this->on_key_up(((KeyUpEvent *) event)->key_code, ((KeyUpEvent *) event)->keyboard_state);
+ break;
- default:
- break;
- }
+ default:
+ break;
+ }
- return event;
+ return event;
}
-
-
-///___Driver___
-
KeyboardDriver::KeyboardDriver()
: InterruptHandler(0x21, 0x1, 0x12),
m_data_port(0x60),
@@ -79,44 +66,41 @@ KeyboardDriver::KeyboardDriver()
}
-KeyboardDriver::~KeyboardDriver()= default;
+KeyboardDriver::~KeyboardDriver() = default;
/**
* @brief activate the keyboard driver
*/
void KeyboardDriver::activate() {
- // Wait for user to stop pressing key (this is for the start-up key e.g. hold 'F12' for boot menu or hold 'del' for bios )
- while (m_command_port.read() & 0x1)
- m_data_port.read();
+ // Wait for user to stop pressing key (this is for the start-up key e.g. hold 'F12' for boot menu or hold 'del' for bios )
+ while (m_command_port.read() & 0x1)
+ m_data_port.read();
- // Enable keyboard interrupts
- m_command_port.write(0xAE);
+ // Enable keyboard interrupts
+ m_command_port.write(0xAE);
- // Get the current state of the keyboard
- m_command_port.write(0x20);
- uint8_t status = (m_data_port.read() | 1) & ~ 0x10;
+ // Get the current state of the keyboard
+ m_command_port.write(0x20);
+ uint8_t status = (m_data_port.read() | 1) & ~0x10;
- // Reset the keyboard
- m_command_port.write(0x60);
- m_data_port.write(status);
+ // Reset the keyboard
+ m_command_port.write(0x60);
+ m_data_port.write(status);
- // activate the keyboard
- m_data_port.write(0xF4);
+ // Activate the keyboard
+ m_data_port.write(0xF4);
}
/**
* @brief deactivate the keyboard driver
*/
-void KeyboardDriver::handle_interrupt(){
-
- // read the scancode from the keyboard
- uint8_t key = m_data_port.read();
+void KeyboardDriver::handle_interrupt() {
- // Pass the scan code to the m_handlers
- for(auto& handler : this -> m_input_stream_event_handlers){
- handler -> on_stream_read(key);
- }
+ // Pass the scan code to the m_handlers
+ uint8_t key = m_data_port.read();
+ for (auto &handler: m_input_stream_event_handlers)
+ handler->on_stream_read(key);
}
/**
@@ -124,18 +108,13 @@ void KeyboardDriver::handle_interrupt(){
* @return The device name
*/
string KeyboardDriver::device_name() {
- return "Keyboard";
+ return "Keyboard";
}
-///___State___
-
-
KeyboardState::KeyboardState() = default;
KeyboardState::~KeyboardState() = default;
-///___Interpreter___
-
KeyboardInterpreter::KeyboardInterpreter()
: InputStreamEventHandler()
{
@@ -144,18 +123,16 @@ KeyboardInterpreter::KeyboardInterpreter()
KeyboardInterpreter::~KeyboardInterpreter() = default;
-void KeyboardInterpreter::on_key_read(bool released, const KeyboardState& state, KeyCode key_code) {
+void KeyboardInterpreter::on_key_read(bool released, const KeyboardState &state, KeyCode key_code) {
- // Pass the key event to the handlers
- if(released)
- raise_event(new KeyUpEvent(key_code, state));
- else
- raise_event(new KeyDownEvent(key_code, state));
+ // Pass the key event to the handlers
+ if (released)
+ raise_event(new KeyUpEvent(key_code, state));
+ else
+ raise_event(new KeyDownEvent(key_code, state));
}
-///___Interpreter EN_US___
-
KeyboardInterpreterEN_US::KeyboardInterpreterEN_US()
: KeyboardInterpreter()
{
@@ -171,543 +148,491 @@ KeyboardInterpreterEN_US::~KeyboardInterpreterEN_US() = default;
*/
void KeyboardInterpreterEN_US::on_stream_read(uint8_t scan_code) {
- // 0 is a regular key, 1 is an extended code, 2 is an extended code with e1CodeBuffer
- int keyType = 0;
-
- // Check if the key was released
- bool released = (scan_code & 0x80) && (m_current_extended_code_1 || (scan_code != 0xe1)) && (m_next_is_extended_code_0 || (scan_code != 0xe0));
-
- // Clear the released bit
- if (released)
- scan_code &= ~0x80;
-
- // Set the e0Code flag to true
- if (scan_code == 0xe0)
- {
- m_next_is_extended_code_0 = true;
- return;
- }
-
- // If e0Code is true, set keyType to 1 and reset e0Code
- if (m_next_is_extended_code_0)
- {
- keyType = 1;
- m_next_is_extended_code_0 = false;
-
- // Check if the scan_code represents a shift key and return (fake shift)
- if ((KeyboardInterpreterEN_US::KeyCodeEN_US)scan_code == KeyCodeEN_US::leftShift || (KeyboardInterpreterEN_US::KeyCodeEN_US)scan_code == KeyCodeEN_US::rightShift)
- return;
- }
-
- // If the scan_code is 0xe1, set the e1Code flag to 1 and return
- if (scan_code == 0xe1)
- {
- m_current_extended_code_1 = 1;
- return;
- }
-
- // If e1Code is 1, set e1Code to 2, store the scan_code in e1CodeBuffer, and return
- if (m_current_extended_code_1 == 1)
- {
- m_current_extended_code_1 = 2;
- m_extended_code_1_buffer = scan_code;
- return;
- }
-
- // If e1Code is 2, set keyType to 2, reset e1Code, and update e1CodeBuffer
- if (m_current_extended_code_1 == 2)
- {
- keyType = 2;
- m_current_extended_code_1 = 0;
- m_extended_code_1_buffer |= (((uint16_t)scan_code) << 8);
- }
-
- bool is_shifting = this ->m_keyboard_state.left_shift || this ->m_keyboard_state.right_shift;
- bool should_be_upper_case = is_shifting != this ->m_keyboard_state.caps_lock;
-
-
- // TODO: Probably a better way to do this (investigate when adding more keyboard layouts)
- if(keyType == 0)
- switch ((KeyCodeEN_US)scan_code) {
-
- // First row
- case KeyCodeEN_US::escape:
- on_key_read(released, this ->m_keyboard_state, KeyCode::escape);
- break;
-
- case KeyCodeEN_US::f1:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f1);
- break;
-
- case KeyCodeEN_US::f2:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f2);
- break;
-
- case KeyCodeEN_US::f3:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f3);
- break;
-
- case KeyCodeEN_US::f4:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f4);
- break;
-
- case KeyCodeEN_US::f5:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f5);
- break;
-
- case KeyCodeEN_US::f6:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f6);
- break;
-
- case KeyCodeEN_US::f7:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f7);
- break;
-
- case KeyCodeEN_US::f8:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f8);
- break;
-
- case KeyCodeEN_US::f9:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f9);
- break;
-
- case KeyCodeEN_US::f10:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f10);
- break;
-
- case KeyCodeEN_US::f11:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f11);
- break;
-
- case KeyCodeEN_US::f12:
- on_key_read(released, this ->m_keyboard_state, KeyCode::f12);
- break;
-
- case KeyCodeEN_US::printScreen:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock
- ? KeyCode::numberPadMultiply : KeyCode::printScreen);
- break;
-
- case KeyCodeEN_US::scrollLock:
- on_key_read(released, this ->m_keyboard_state, KeyCode::scrollLock);
- break;
-
- // Second row
- case KeyCodeEN_US::squigglyLine:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::squigglyLine : KeyCode::slantedApostrophe);
- break;
-
- case KeyCodeEN_US::one:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::exclamationMark : KeyCode::one);
- break;
-
- case KeyCodeEN_US::two:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::atSign: KeyCode::two);
- break;
-
- case KeyCodeEN_US::three:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::hash : KeyCode::three);
- break;
-
- case KeyCodeEN_US::four:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::dollarSign : KeyCode::four);
- break;
-
- case KeyCodeEN_US::five:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::percentSign : KeyCode::five);
- break;
-
- case KeyCodeEN_US::six:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::powerSign : KeyCode::six);
- break;
-
- case KeyCodeEN_US::seven:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::andSign : KeyCode::seven);
- break;
-
- case KeyCodeEN_US::eight:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::multiply : KeyCode::eight);
- break;
-
- case KeyCodeEN_US::nine:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::openBracket : KeyCode::nine);
- break;
-
- case KeyCodeEN_US::zero:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::closeBracket : KeyCode::zero);
- break;
-
- case KeyCodeEN_US::minus:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::underscore : KeyCode::minus);
- break;
-
- case KeyCodeEN_US::equals:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::plus : KeyCode::equals);
- break;
-
- case KeyCodeEN_US::backspace:
- on_key_read(released, this ->m_keyboard_state, KeyCode::backspace);
- break;
-
- case KeyCodeEN_US::insert:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock ? KeyCode::numberPadZero : KeyCode::insert);
- break;
-
- case KeyCodeEN_US::home:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock
- ? KeyCode::numberPadSeven : KeyCode::home);
- break;
-
- case KeyCodeEN_US::pageUp:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock ? KeyCode::numberPadNine : KeyCode::pageUp);
- break;
-
- case KeyCodeEN_US::numberPadLock:
-
- // Ensure this is not a repeat
- if(!released){
- this ->m_keyboard_state.number_pad_lock = !this ->m_keyboard_state.number_pad_lock;
- }
- on_key_read(released, this ->m_keyboard_state, KeyCode::numberPadLock);
- break;
-
- case KeyCodeEN_US::numberPadForwardSlash:
-
- // Check if number pad lock is on
- if(this ->m_keyboard_state.number_pad_lock){
- on_key_read(released, this ->m_keyboard_state, KeyCode::numberPadForwardSlash);
- }else{
-
- // Normal Forward Slash
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::questionMark : KeyCode::forwardSlash);
- }
- break;
-
- // Number Pad Multiply is same as print screen
-
- case KeyCodeEN_US::numberPadMinus:
- on_key_read(released, this ->m_keyboard_state, KeyCode::numberPadMinus);
- break;
-
- // Third row
- case KeyCodeEN_US::tab:
- on_key_read(released, this ->m_keyboard_state, KeyCode::tab);
- break;
-
- case KeyCodeEN_US::Q:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::Q : KeyCode::q);
- break;
-
- case KeyCodeEN_US::W:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::W : KeyCode::w);
- break;
-
- case KeyCodeEN_US::E:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::E : KeyCode::e);
- break;
-
- case KeyCodeEN_US::R:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::R : KeyCode::r);
- break;
-
- case KeyCodeEN_US::T:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::T : KeyCode::t);
- break;
-
- case KeyCodeEN_US::Y:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::Y : KeyCode::y);
- break;
-
- case KeyCodeEN_US::U:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::U : KeyCode::u);
- break;
-
- case KeyCodeEN_US::I:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::I : KeyCode::i);
- break;
-
- case KeyCodeEN_US::O:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::O : KeyCode::o);
- break;
-
- case KeyCodeEN_US::P:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::P : KeyCode::p);
- break;
-
- case KeyCodeEN_US::openSquareBracket:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::openCurlyBracket : KeyCode::openSquareBracket);
- break;
-
- case KeyCodeEN_US::closeSquareBracket:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::closeCurlyBracket : KeyCode::closeSquareBracket);
- break;
-
- case KeyCodeEN_US::backslash:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::lineThing : KeyCode::backslash);
- break;
-
- case KeyCodeEN_US::deleteKey:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock
- ? KeyCode::numberPadFullStop : KeyCode::deleteKey);
- break;
-
- case KeyCodeEN_US::end:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock ? KeyCode::numberPadOne : KeyCode::end);
- break;
-
- case KeyCodeEN_US::pageDown:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock
- ? KeyCode::numberPadThree : KeyCode::pageDown);
- break;
-
- // Number pad 7 is same as home
-
- case KeyCodeEN_US::numberPadEight:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock
- ? KeyCode::numberPadEight : KeyCode::upArrow);
- break;
-
- // Number pad 9 is same as page up
-
- case KeyCodeEN_US::numberPadPlus:
- on_key_read(released, this ->m_keyboard_state, KeyCode::numberPadPlus);
- break;
-
- // Fourth row
-
- case KeyCodeEN_US::capsLock:
- // Ensure this is not a repeat
- if(!released){
- this ->m_keyboard_state.caps_lock = !this ->m_keyboard_state.caps_lock;
- }
-
- on_key_read(released, this ->m_keyboard_state, KeyCode::capsLock);
- break;
-
- case KeyCodeEN_US::A:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::A : KeyCode::a);
- break;
-
- case KeyCodeEN_US::S:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::S : KeyCode::s);
- break;
-
- case KeyCodeEN_US::D:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::D : KeyCode::d);
- break;
-
- case KeyCodeEN_US::F:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::F : KeyCode::f);
- break;
-
- case KeyCodeEN_US::G:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::G : KeyCode::g);
- break;
-
- case KeyCodeEN_US::H:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::H : KeyCode::h);
- break;
-
- case KeyCodeEN_US::J:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::J : KeyCode::j);
- break;
-
- case KeyCodeEN_US::K:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::K : KeyCode::k);
- break;
-
- case KeyCodeEN_US::L:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::L : KeyCode::l);
- break;
-
- case KeyCodeEN_US::semicolon:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::colon : KeyCode::semicolon);
- break;
-
- case KeyCodeEN_US::apostrophe:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::quotationMark : KeyCode::apostrophe);
- break;
-
- case KeyCodeEN_US::enter:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock
- ? KeyCode::numberPadEnter : KeyCode::enter);
- break;
-
- case KeyCodeEN_US::numberPadFour:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock ? KeyCode::numberPadFour : KeyCode::leftArrow);
- break;
-
- case KeyCodeEN_US::numberPadFive:
- on_key_read(released, this ->m_keyboard_state, KeyCode::numberPadFive);
- break;
-
- case KeyCodeEN_US::numberPadSix:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock ? KeyCode::numberPadSix : KeyCode::rightArrow);
- break;
-
- // Fifth row
- case KeyCodeEN_US::leftShift:
- this ->m_keyboard_state.left_shift = !this ->m_keyboard_state.left_shift;
- on_key_read(released, this ->m_keyboard_state, KeyCode::leftShift);
- break;
-
- case KeyCodeEN_US::Z:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::Z : KeyCode::z);
- break;
-
- case KeyCodeEN_US::X:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::X : KeyCode::x);
- break;
-
- case KeyCodeEN_US::C:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::C : KeyCode::c);
- break;
-
- case KeyCodeEN_US::V:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::V : KeyCode::v);
- break;
-
- case KeyCodeEN_US::B:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::B : KeyCode::b);
- break;
-
- case KeyCodeEN_US::N:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::N : KeyCode::n);
- break;
-
- case KeyCodeEN_US::M:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::M : KeyCode::m);
- break;
-
- case KeyCodeEN_US::comma:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::lessThan : KeyCode::comma);
- break;
-
- case KeyCodeEN_US::fullStop:
- on_key_read(released, this ->m_keyboard_state,
- should_be_upper_case ? KeyCode::greaterThan : KeyCode::fullStop);
- break;
-
- // Forward slash is same as number pad forward slash
- case KeyCodeEN_US::rightShift:
- // Check if this is a repeat
- if(!released){
- this ->m_keyboard_state.right_shift = !this ->m_keyboard_state.right_shift;
- }
-
- on_key_read(released, this ->m_keyboard_state, KeyCode::rightShift);
- break;
+ // Check if the key was released
+ bool released = (scan_code & 0x80) && (m_current_extended_code_1
+ || (scan_code != 0xe1)) && (m_next_is_extended_code_0
+ || (scan_code != 0xe0));
+
+ // Clear the released bit
+ if (released)
+ scan_code &= ~0x80;
+
+ // Start of an extended scan code
+ if (scan_code == 0xe0) {
+ m_next_is_extended_code_0 = true;
+ return;
+ }
+
+ // Handle extended scan codes
+ ScanCodeType type = ScanCodeType::REGULAR;
+ if (m_next_is_extended_code_0) {
+
+ type = ScanCodeType::EXTENDED;
+ m_next_is_extended_code_0 = false;
+
+ // Check if the scan_code represents a shift key and return (fake shift)
+ if ((KeyboardInterpreterEN_US::KeyCodeEN_US) scan_code == KeyCodeEN_US::leftShift ||
+ (KeyboardInterpreterEN_US::KeyCodeEN_US) scan_code == KeyCodeEN_US::rightShift)
+ return;
+ }
+
+ // If the scan_code is 0xe1, set the e1Code flag to 1 and return
+ if (scan_code == 0xe1) {
+ m_current_extended_code_1 = 1;
+ return;
+ }
+
+ // If e1Code is 1, set e1Code to 2, store the scan_code in e1CodeBuffer, and return
+ if (m_current_extended_code_1 == 1) {
+ m_current_extended_code_1 = 2;
+ m_extended_code_1_buffer = scan_code;
+ return;
+ }
+
+ // If e1Code is 2, set keyType to 2, reset e1Code, and update e1CodeBuffer
+ if (m_current_extended_code_1 == 2) {
+ type = ScanCodeType::EXTENDED;
+ m_current_extended_code_1 = 0;
+ m_extended_code_1_buffer |= (((uint16_t) scan_code) << 8);
+ }
+
+ // Scan code value manipulations
+ bool is_shifting = this->m_keyboard_state.left_shift || this->m_keyboard_state.right_shift;
+ bool should_be_upper_case = is_shifting != this->m_keyboard_state.caps_lock;
+
+ // TODO: Probably a better way to do this (investigate when adding more keyboard layouts)
+ if (type == ScanCodeType::REGULAR)
+ switch ((KeyCodeEN_US) scan_code) {
+
+ /// First row
+ case KeyCodeEN_US::escape:
+ on_key_read(released, this->m_keyboard_state, KeyCode::escape);
+ break;
+
+ case KeyCodeEN_US::f1:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f1);
+ break;
+
+ case KeyCodeEN_US::f2:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f2);
+ break;
+
+ case KeyCodeEN_US::f3:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f3);
+ break;
+
+ case KeyCodeEN_US::f4:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f4);
+ break;
+
+ case KeyCodeEN_US::f5:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f5);
+ break;
+
+ case KeyCodeEN_US::f6:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f6);
+ break;
+
+ case KeyCodeEN_US::f7:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f7);
+ break;
+
+ case KeyCodeEN_US::f8:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f8);
+ break;
+
+ case KeyCodeEN_US::f9:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f9);
+ break;
+
+ case KeyCodeEN_US::f10:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f10);
+ break;
+
+ case KeyCodeEN_US::f11:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f11);
+ break;
+
+ case KeyCodeEN_US::f12:
+ on_key_read(released, this->m_keyboard_state, KeyCode::f12);
+ break;
+
+ case KeyCodeEN_US::printScreen:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock ? KeyCode::numberPadMultiply : KeyCode::printScreen);
+ break;
+
+ case KeyCodeEN_US::scrollLock:
+ on_key_read(released, this->m_keyboard_state, KeyCode::scrollLock);
+ break;
+
+ /// Second row
+ case KeyCodeEN_US::squigglyLine:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::squigglyLine : KeyCode::slantedApostrophe);
+ break;
+
+ case KeyCodeEN_US::one:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::exclamationMark : KeyCode::one);
+ break;
+
+ case KeyCodeEN_US::two:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::atSign : KeyCode::two);
+ break;
+
+ case KeyCodeEN_US::three:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::hash : KeyCode::three);
+ break;
+
+ case KeyCodeEN_US::four:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::dollarSign : KeyCode::four);
+ break;
+
+ case KeyCodeEN_US::five:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::percentSign : KeyCode::five);
+ break;
+
+ case KeyCodeEN_US::six:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::powerSign : KeyCode::six);
+ break;
+
+ case KeyCodeEN_US::seven:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::andSign : KeyCode::seven);
+ break;
+
+ case KeyCodeEN_US::eight:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::multiply : KeyCode::eight);
+ break;
+
+ case KeyCodeEN_US::nine:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::openBracket : KeyCode::nine);
+ break;
+
+ case KeyCodeEN_US::zero:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::closeBracket : KeyCode::zero);
+ break;
+
+ case KeyCodeEN_US::minus:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::underscore : KeyCode::minus);
+ break;
+
+ case KeyCodeEN_US::equals:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::plus : KeyCode::equals);
+ break;
+
+ case KeyCodeEN_US::backspace:
+ on_key_read(released, this->m_keyboard_state, KeyCode::backspace);
+ break;
+
+ case KeyCodeEN_US::insert:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock ? KeyCode::numberPadZero : KeyCode::insert);
+ break;
+
+ case KeyCodeEN_US::home:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock
+ ? KeyCode::numberPadSeven : KeyCode::home);
+ break;
+
+ case KeyCodeEN_US::pageUp:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock ? KeyCode::numberPadNine : KeyCode::pageUp);
+ break;
+
+ case KeyCodeEN_US::numberPadLock:
+
+ // Ensure this is not a repeat
+ if (!released) {
+ this->m_keyboard_state.number_pad_lock = !this->m_keyboard_state.number_pad_lock;
+ }
+ on_key_read(released, this->m_keyboard_state, KeyCode::numberPadLock);
+ break;
+
+ case KeyCodeEN_US::numberPadForwardSlash:
+
+ // Check if number pad lock is on
+ if (this->m_keyboard_state.number_pad_lock) {
+ on_key_read(released, this->m_keyboard_state, KeyCode::numberPadForwardSlash);
+ } else {
+
+ // Normal Forward Slash
+ on_key_read(released, this->m_keyboard_state,
+ should_be_upper_case ? KeyCode::questionMark : KeyCode::forwardSlash);
+ }
+ break;
+
+ // Number Pad Multiply is same as print screen
+
+ case KeyCodeEN_US::numberPadMinus:
+ on_key_read(released, this->m_keyboard_state, KeyCode::numberPadMinus);
+ break;
+
+ // Third row
+ case KeyCodeEN_US::tab:
+ on_key_read(released, this->m_keyboard_state, KeyCode::tab);
+ break;
+
+ case KeyCodeEN_US::Q:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::Q : KeyCode::q);
+ break;
+
+ case KeyCodeEN_US::W:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::W : KeyCode::w);
+ break;
+
+ case KeyCodeEN_US::E:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::E : KeyCode::e);
+ break;
+
+ case KeyCodeEN_US::R:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::R : KeyCode::r);
+ break;
+
+ case KeyCodeEN_US::T:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::T : KeyCode::t);
+ break;
+
+ case KeyCodeEN_US::Y:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::Y : KeyCode::y);
+ break;
+
+ case KeyCodeEN_US::U:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::U : KeyCode::u);
+ break;
+
+ case KeyCodeEN_US::I:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::I : KeyCode::i);
+ break;
+
+ case KeyCodeEN_US::O:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::O : KeyCode::o);
+ break;
+
+ case KeyCodeEN_US::P:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::P : KeyCode::p);
+ break;
+
+ case KeyCodeEN_US::openSquareBracket:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::openCurlyBracket : KeyCode::openSquareBracket);
+ break;
+
+ case KeyCodeEN_US::closeSquareBracket:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::closeCurlyBracket : KeyCode::closeSquareBracket);
+ break;
+
+ case KeyCodeEN_US::backslash:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::lineThing : KeyCode::backslash);
+ break;
+
+ case KeyCodeEN_US::deleteKey:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock
+ ? KeyCode::numberPadFullStop : KeyCode::deleteKey);
+ break;
+
+ case KeyCodeEN_US::end:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock ? KeyCode::numberPadOne : KeyCode::end);
+ break;
+
+ case KeyCodeEN_US::pageDown:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock
+ ? KeyCode::numberPadThree : KeyCode::pageDown);
+ break;
+
+ // Number pad 7 is same as home
+
+ case KeyCodeEN_US::numberPadEight:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock ? KeyCode::numberPadEight : KeyCode::upArrow);
+ break;
+
+ // Number pad 9 is same as page up
+
+ case KeyCodeEN_US::numberPadPlus:
+ on_key_read(released, this->m_keyboard_state, KeyCode::numberPadPlus);
+ break;
+
+ /// Fourth row
+ case KeyCodeEN_US::capsLock:
+ // Ensure this is not a repeat
+ if (!released) {
+ this->m_keyboard_state.caps_lock = !this->m_keyboard_state.caps_lock;
+ }
+
+ on_key_read(released, this->m_keyboard_state, KeyCode::capsLock);
+ break;
+
+ case KeyCodeEN_US::A:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::A : KeyCode::a);
+ break;
+
+ case KeyCodeEN_US::S:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::S : KeyCode::s);
+ break;
+
+ case KeyCodeEN_US::D:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::D : KeyCode::d);
+ break;
+
+ case KeyCodeEN_US::F:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::F : KeyCode::f);
+ break;
+
+ case KeyCodeEN_US::G:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::G : KeyCode::g);
+ break;
+
+ case KeyCodeEN_US::H:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::H : KeyCode::h);
+ break;
+
+ case KeyCodeEN_US::J:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::J : KeyCode::j);
+ break;
+
+ case KeyCodeEN_US::K:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::K : KeyCode::k);
+ break;
+
+ case KeyCodeEN_US::L:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::L : KeyCode::l);
+ break;
+
+ case KeyCodeEN_US::semicolon:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::colon : KeyCode::semicolon);
+ break;
+
+ case KeyCodeEN_US::apostrophe:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::quotationMark : KeyCode::apostrophe);
+ break;
+
+ case KeyCodeEN_US::enter:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock ? KeyCode::numberPadEnter : KeyCode::enter);
+ break;
+
+ case KeyCodeEN_US::numberPadFour:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock ? KeyCode::numberPadFour : KeyCode::leftArrow);
+ break;
+
+ case KeyCodeEN_US::numberPadFive:
+ on_key_read(released, this->m_keyboard_state, KeyCode::numberPadFive);
+ break;
+
+ case KeyCodeEN_US::numberPadSix:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock ? KeyCode::numberPadSix : KeyCode::rightArrow);
+ break;
+
+ /// Fifth row
+ case KeyCodeEN_US::leftShift:
+ this->m_keyboard_state.left_shift = !this->m_keyboard_state.left_shift;
+ on_key_read(released, this->m_keyboard_state, KeyCode::leftShift);
+ break;
+
+ case KeyCodeEN_US::Z:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::Z : KeyCode::z);
+ break;
+
+ case KeyCodeEN_US::X:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::X : KeyCode::x);
+ break;
+
+ case KeyCodeEN_US::C:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::C : KeyCode::c);
+ break;
+
+ case KeyCodeEN_US::V:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::V : KeyCode::v);
+ break;
+
+ case KeyCodeEN_US::B:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::B : KeyCode::b);
+ break;
+
+ case KeyCodeEN_US::N:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::N : KeyCode::n);
+ break;
+
+ case KeyCodeEN_US::M:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::M : KeyCode::m);
+ break;
+
+ case KeyCodeEN_US::comma:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::lessThan : KeyCode::comma);
+ break;
+
+ case KeyCodeEN_US::fullStop:
+ on_key_read(released, this->m_keyboard_state, should_be_upper_case ? KeyCode::greaterThan : KeyCode::fullStop);
+ break;
+
+ // Forward slash is same as number pad forward slash
+
+ case KeyCodeEN_US::rightShift:
+ // Check if this is a repeat
+ if (!released) {
+ this->m_keyboard_state.right_shift = !this->m_keyboard_state.right_shift;
+ }
+
+ on_key_read(released, this->m_keyboard_state, KeyCode::rightShift);
+ break;
+
+ // Up Arrow is the same as number pad 8
+
+ // Number pad 1 is the same as end
- // Up Arrow is the same as number pad 8
+ case KeyCodeEN_US::numberPadTwo:
+ on_key_read(released, this->m_keyboard_state, this->m_keyboard_state.number_pad_lock ? KeyCode::numberPadTwo : KeyCode::downArrow);
+ break;
- // Number pad 1 is the same as end
+ // Number pad 3 is the same as page down
- case KeyCodeEN_US::numberPadTwo:
- on_key_read(released, this ->m_keyboard_state, this ->m_keyboard_state.number_pad_lock ? KeyCode::numberPadTwo : KeyCode::downArrow);
- break;
+ // Number pad enter is the same as enter
- // Number pad 3 is the same as page down
+ /// Sixth row
+ case KeyCodeEN_US::leftControl:
+ // Check if this is a repeat
+ if (!released) {
+ this->m_keyboard_state.left_control = !this->m_keyboard_state.left_control;
+ this->m_keyboard_state.right_control = !this->m_keyboard_state.right_control;
+ }
- // Number pad enter is the same as enter
+ on_key_read(released, this->m_keyboard_state, KeyCode::leftControl);
+ break;
- // Sixth row
- case KeyCodeEN_US::leftControl:
- // Check if this is a repeat
- if(!released){
- this ->m_keyboard_state.left_control = !this ->m_keyboard_state.left_control;
- this ->m_keyboard_state.right_control = !this ->m_keyboard_state.right_control;
- }
+ case KeyCodeEN_US::leftOS:
+ on_key_read(released, this->m_keyboard_state, KeyCode::leftOS);
+ break;
- on_key_read(released, this ->m_keyboard_state, KeyCode::leftControl);
- break;
+ case KeyCodeEN_US::leftAlt:
+ // Check if this is a repeat
+ if (!released) {
+ this->m_keyboard_state.left_alt = !this->m_keyboard_state.left_alt;
+ this->m_keyboard_state.right_alt = !this->m_keyboard_state.right_alt;
+ }
- case KeyCodeEN_US::leftOS:
- on_key_read(released, this ->m_keyboard_state, KeyCode::leftOS);
- break;
+ on_key_read(released, this->m_keyboard_state, KeyCode::leftAlt);
+ break;
- case KeyCodeEN_US::leftAlt:
- // Check if this is a repeat
- if(!released){
- this ->m_keyboard_state.left_alt = !this ->m_keyboard_state.left_alt;
- this ->m_keyboard_state.right_alt = !this ->m_keyboard_state.right_alt;
- }
+ case KeyCodeEN_US::space:
+ on_key_read(released, this->m_keyboard_state, KeyCode::space);
+ break;
- on_key_read(released, this ->m_keyboard_state, KeyCode::leftAlt);
- break;
+ // Right Alt is the same as left alt
- case KeyCodeEN_US::space:
- on_key_read(released, this ->m_keyboard_state, KeyCode::space);
- break;
+ // Right Control is the same as left control
- // Right Alt is the same as left alt
+ // Left Arrow is the same as number pad 4
- // Right Control is the same as left control
+ // Down Arrow is the same as number pad 2
- // Left Arrow is the same as number pad 4
+ // Right Arrow is the same as number pad 6
- // Down Arrow is the same as number pad 2
+ // Number pad 0 is the same as insert
- // Right Arrow is the same as number pad 6
+ // Number pad full stop is the same as delete
- // Number pad 0 is the same as insert
+ default:
+ break;
- // Number pad full stop is the same as delete
+ }
- default:
- break;
-
- }
-
}
-KeyDownEvent::KeyDownEvent(KeyCode keyCode, const KeyboardState& keyboardState)
+KeyDownEvent::KeyDownEvent(KeyCode keyCode, const KeyboardState &keyboardState)
: Event(KeyboardEvents::KEYDOWN),
key_code(keyCode),
keyboard_state(keyboardState)
@@ -716,7 +641,7 @@ KeyDownEvent::KeyDownEvent(KeyCode keyCode, const KeyboardState& keyboardState)
KeyDownEvent::~KeyDownEvent() = default;
-KeyUpEvent::KeyUpEvent(KeyCode key_code, const KeyboardState& keyboard_state)
+KeyUpEvent::KeyUpEvent(KeyCode key_code, const KeyboardState &keyboard_state)
: Event(KeyboardEvents::KEYUP),
key_code(key_code),
keyboard_state(keyboard_state)
diff --git a/kernel/src/drivers/peripherals/mouse.cpp b/kernel/src/drivers/peripherals/mouse.cpp
index 31b68471..bc5841da 100644
--- a/kernel/src/drivers/peripherals/mouse.cpp
+++ b/kernel/src/drivers/peripherals/mouse.cpp
@@ -10,9 +10,6 @@ using namespace MaxOS::drivers;
using namespace MaxOS::drivers::peripherals;
using namespace MaxOS::hardwarecommunication;
-
-///__Handler__
-
MouseEventHandler::MouseEventHandler() = default;
/**
@@ -21,26 +18,25 @@ MouseEventHandler::MouseEventHandler() = default;
* @param event The event that was triggered
* @return The event that was triggered with the modified data
*/
-Event* MouseEventHandler::on_event(Event *event) {
- switch (event->type){
+Event *MouseEventHandler::on_event(Event *event) {
+ switch (event->type) {
- case MouseEvents::MOVE:
- this->on_mouse_move_event(((MouseMoveEvent *)event)->x,
- ((MouseMoveEvent *)event)->y);
- break;
+ case MouseEvents::MOVE:
+ this->on_mouse_move_event(((MouseMoveEvent *) event)->x,
+ ((MouseMoveEvent *) event)->y);
+ break;
- case MouseEvents::DOWN:
- this->on_mouse_down_event(((MouseDownEvent *)event)->button);
- break;
+ case MouseEvents::DOWN:
+ this->on_mouse_down_event(((MouseDownEvent *) event)->button);
+ break;
- case MouseEvents::UP:
- this->on_mouse_up_event(((MouseUpEvent *)event)->button);
- break;
+ case MouseEvents::UP:
+ this->on_mouse_up_event(((MouseUpEvent *) event)->button);
+ break;
- }
+ }
- // Return the event
- return event;
+ return event;
}
/**
@@ -48,7 +44,7 @@ Event* MouseEventHandler::on_event(Event *event) {
*
* @param button The button that was pressed
*/
-void MouseEventHandler::on_mouse_down_event(uint8_t){
+void MouseEventHandler::on_mouse_down_event(uint8_t) {
}
@@ -57,7 +53,7 @@ void MouseEventHandler::on_mouse_down_event(uint8_t){
*
* @param button The button that was released
*/
-void MouseEventHandler::on_mouse_up_event(uint8_t){
+void MouseEventHandler::on_mouse_up_event(uint8_t) {
}
@@ -67,14 +63,12 @@ void MouseEventHandler::on_mouse_up_event(uint8_t){
* @param x How much the mouse moved in the x direction
* @param y How much the mouse moved in the y direction
*/
-void MouseEventHandler::on_mouse_move_event(int8_t, int8_t){
+void MouseEventHandler::on_mouse_move_event(int8_t, int8_t) {
}
MouseEventHandler::~MouseEventHandler() = default;
-///__Driver__
-
MouseDriver::MouseDriver()
: InterruptHandler(0x2C, 0xC, 0x28),
data_port(0x60),
@@ -82,70 +76,69 @@ MouseDriver::MouseDriver()
{
}
-MouseDriver::~MouseDriver()= default;
+
+MouseDriver::~MouseDriver() = default;
/**
* @brief activate the mouse
*/
void MouseDriver::activate() {
+ // Get the current state of the mouse
+ command_port.write(0x20);
+ uint8_t status = (data_port.read() | 2);
+ // Write the new state
+ command_port.write(0x60);
+ data_port.write(status);
- // Get the current state of the mouse
- command_port.write(0x20);
- uint8_t status = (data_port.read() | 2);
+ // Tell the PIC to start listening to the mouse
+ command_port.write(0xAB);
- // write the new state
- command_port.write(0x60);
- data_port.write(status);
-
- // Tell the PIC to start listening to the mouse
- command_port.write(0xAB);
-
- // activate the mouse
- command_port.write(0xD4);
- data_port.write(0xF4);
- data_port.read();
+ // Activate the mouse
+ command_port.write(0xD4);
+ data_port.write(0xF4);
+ data_port.read();
}
/**
* @brief Handle the mouse interrupt
*/
-void MouseDriver::handle_interrupt(){
+void MouseDriver::handle_interrupt() {
- //Only if the 6th bit of data is one then there is data to handle
- uint8_t status = command_port.read();
- if(!(status & 0x20))
- return;
+ // Check if there is data to handle
+ uint8_t status = command_port.read();
+ if (!(status & 0x20))
+ return;
- // read the data and store it in the buffer
- buffer[offset] = data_port.read();
- offset = (offset + 1) % 3;
+ // Read the data
+ m_buffer[m_offset] = data_port.read();
+ m_offset = (m_offset + 1) % 3;
- // If the mouse data transmission is incomplete (3rd piece of data isn't through)
- if(offset != 0)
- return;
+ // If the mouse data transmission is incomplete (3rd piece of data isn't through)
+ if (m_offset != 0)
+ return;
- // If the mouse is moved (y-axis is inverted)
- if(buffer[1] != 0 || buffer[2] != 0)
- raise_event(new MouseMoveEvent(buffer[1], -buffer[2]));
+ // If the mouse is moved (y-axis is inverted)
+ if (m_buffer[1] != 0 || m_buffer[2] != 0)
+ raise_event(new MouseMoveEvent(m_buffer[1], -m_buffer[2]));
- for (int i = 0; i < 3; ++i) {
+ // Handle button presses
+ for (int i = 0; i < 3; ++i) {
- // Check if the button state has changed
- if((buffer[0] & (0x1<(MouseEvents::UP),
button(button)
@@ -183,4 +174,4 @@ MouseMoveEvent::MouseMoveEvent(int8_t x, int8_t y)
{
}
-MouseMoveEvent::~MouseMoveEvent() = default;
+MouseMoveEvent::~MouseMoveEvent() = default;
\ No newline at end of file
diff --git a/kernel/src/drivers/video/vesa.cpp b/kernel/src/drivers/video/vesa.cpp
index f8b98c0d..cc0639ed 100644
--- a/kernel/src/drivers/video/vesa.cpp
+++ b/kernel/src/drivers/video/vesa.cpp
@@ -12,60 +12,36 @@ using namespace MaxOS::memory;
using namespace MaxOS::system;
using namespace MaxOS::common;
-VideoElectronicsStandardsAssociation::VideoElectronicsStandardsAssociation(multiboot_tag_framebuffer* framebuffer_info)
-: VideoDriver(),
- m_framebuffer_info(framebuffer_info)
+VideoElectronicsStandardsAssociation::VideoElectronicsStandardsAssociation(multiboot_tag_framebuffer *framebuffer_info)
+: m_framebuffer_info(framebuffer_info)
{
- // Get the framebuffer info
- Logger::INFO() << "Setting up VESA driver\n";
- Logger::DEBUG() << "Framebuffer info: 0x " << (uint64_t)m_framebuffer_info << "\n";
- // Set the framebuffer address, bpp and pitch
- m_bpp = m_framebuffer_info->common.framebuffer_bpp;
- m_pitch = m_framebuffer_info->common.framebuffer_pitch;
- m_framebuffer_size = m_framebuffer_info->common.framebuffer_height * m_pitch;
+ Logger::INFO() << "Setting up VESA driver\n";
- Logger::DEBUG() << "Framebuffer: bpp=" << m_bpp << ", pitch=" << m_pitch << ", size=" << m_framebuffer_size << "\n";
+ // Save the framebuffer info
+ m_bpp = m_framebuffer_info->common.framebuffer_bpp;
+ m_pitch = m_framebuffer_info->common.framebuffer_pitch;
+ m_framebuffer_size = m_framebuffer_info->common.framebuffer_height * m_pitch;
+ this->set_mode(framebuffer_info->common.framebuffer_width, framebuffer_info->common.framebuffer_height,
+ framebuffer_info->common.framebuffer_bpp);
+ Logger::DEBUG() << "Framebuffer: bpp=" << m_bpp << ", pitch=" << m_pitch << ", size=" << m_framebuffer_size << "\n";
- // Get the framebuffer address
- auto physical_address = (uint64_t)m_framebuffer_info->common.framebuffer_addr;
- auto virtual_address = (uint64_t)PhysicalMemoryManager::to_dm_region(physical_address);
- uint64_t end = physical_address + m_framebuffer_size;
- m_framebuffer_address = (uint64_t*)virtual_address;
+ // Map the frame buffer into the higher half
+ auto physical_address = (uint64_t) m_framebuffer_info->common.framebuffer_addr;
+ m_framebuffer_address = (uint64_t *) PhysicalMemoryManager::to_dm_region(physical_address);
+ PhysicalMemoryManager::s_current_manager->map_area((physical_address_t *) physical_address, m_framebuffer_address, m_framebuffer_size, Write | Present);
- Logger::DEBUG() << "Framebuffer address: physical=0x" << physical_address << ", virtual=0x" << virtual_address << "\n";
+ // Reserve the physical memory
+ size_t pages = PhysicalMemoryManager::size_to_frames(m_framebuffer_size);
+ PhysicalMemoryManager::s_current_manager->reserve(m_framebuffer_info->common.framebuffer_addr, pages);
- // Map the framebuffer
- while (physical_address < end) {
-
- PhysicalMemoryManager::s_current_manager->map((physical_address_t*)physical_address, (virtual_address_t*)virtual_address, Write | Present);
- physical_address += PhysicalMemoryManager::s_page_size;
- virtual_address += PhysicalMemoryManager::s_page_size;
- }
-
- size_t pages = PhysicalMemoryManager::size_to_frames(virtual_address - (uint64_t)m_framebuffer_address);
- Logger::DEBUG() << "Framebuffer mapped: 0x" << (uint64_t)m_framebuffer_address << " - 0x" << virtual_address << " (pages: " << pages << ")\n";
-
- // Reserve the physical memory
- PhysicalMemoryManager::s_current_manager->reserve(m_framebuffer_info->common.framebuffer_addr, pages);
-
- // Set the default video mode
- this -> set_mode(framebuffer_info->common.framebuffer_width,framebuffer_info->common.framebuffer_height, framebuffer_info->common.framebuffer_bpp);
+ // Log info
+ Logger::DEBUG() << "Framebuffer address: physical=0x" << (uint64_t) physical_address << ", virtual=0x" << (uint64_t) m_framebuffer_address << "\n";
+ Logger::DEBUG() << "Framebuffer mapped: 0x" << (uint64_t) m_framebuffer_address << " - 0x" << (uint64_t) (m_framebuffer_address + m_framebuffer_size) << " (pages: " << pages << ")\n";
}
-VideoElectronicsStandardsAssociation::~VideoElectronicsStandardsAssociation()= default;
-
-/**
- * @brief Initializes the VESA driver
- *
- * @return True if the driver was initialized successfully, false otherwise
- */
-bool VideoElectronicsStandardsAssociation::init() {
-
- //Multiboot inits this for us
- return true;
-}
+VideoElectronicsStandardsAssociation::~VideoElectronicsStandardsAssociation() = default;
/**
* @brief Sets the mode of the VESA driver
@@ -75,11 +51,12 @@ bool VideoElectronicsStandardsAssociation::init() {
* @param color_depth Color depth of the screen
* @return True if the mode was set successfully, false otherwise
*/
-bool VideoElectronicsStandardsAssociation::internal_set_mode(uint32_t, uint32_t, uint32_t) {
-
- // Best mode is set by the bootloader
- return true;
+bool VideoElectronicsStandardsAssociation::internal_set_mode(uint32_t width, uint32_t height, uint32_t color_depth) {
+ // Can only use the mode set up already by grub
+ return width == m_framebuffer_info->common.framebuffer_width
+ && height == m_framebuffer_info->common.framebuffer_height
+ && color_depth == m_framebuffer_info->common.framebuffer_bpp;
}
@@ -93,11 +70,10 @@ bool VideoElectronicsStandardsAssociation::internal_set_mode(uint32_t, uint32_t,
*/
bool VideoElectronicsStandardsAssociation::supports_mode(uint32_t width, uint32_t height, uint32_t color_depth) {
- // Check if the mode is supported
- if(width == (uint32_t)m_framebuffer_info->common.framebuffer_width && height == (uint32_t)m_framebuffer_info->common.framebuffer_height && color_depth == (uint32_t)m_framebuffer_info->common.framebuffer_bpp) {
- return true;
- }
- return false;
+ // Check if the mode is supported
+ return width == m_framebuffer_info->common.framebuffer_width
+ && height == m_framebuffer_info->common.framebuffer_height
+ && color_depth == m_framebuffer_info->common.framebuffer_bpp;
}
/**
@@ -109,11 +85,8 @@ bool VideoElectronicsStandardsAssociation::supports_mode(uint32_t width, uint32_
*/
void VideoElectronicsStandardsAssociation::render_pixel_32_bit(uint32_t x, uint32_t y, uint32_t colour) {
- // Get the address of the pixel
- auto* pixel_address = (uint32_t*)((uint8_t *)m_framebuffer_address + m_pitch * (y) + m_bpp * (x) / 8);
-
- // Set the pixel
- *pixel_address = colour;
+ auto *pixel_address = (uint32_t *) ((uint8_t *) m_framebuffer_address + (m_pitch * y) + (m_bpp * x) / 8);
+ *pixel_address = colour;
}
@@ -126,11 +99,8 @@ void VideoElectronicsStandardsAssociation::render_pixel_32_bit(uint32_t x, uint3
*/
uint32_t VideoElectronicsStandardsAssociation::get_rendered_pixel_32_bit(uint32_t x, uint32_t y) {
- // Get the address of the pixel
- auto* pixel_address = (uint32_t*)((uint8_t *)m_framebuffer_address + m_pitch * (y) + m_bpp * (x) / 8);
-
- // Return the pixel
- return *pixel_address;
+ auto *pixel_address = (uint32_t *) ((uint8_t *) m_framebuffer_address + m_pitch * (y) + m_bpp * (x) / 8);
+ return *pixel_address;
}
/**
@@ -139,7 +109,9 @@ uint32_t VideoElectronicsStandardsAssociation::get_rendered_pixel_32_bit(uint32_
* @return The name of the vendor
*/
string VideoElectronicsStandardsAssociation::vendor_name() {
- return "NEC Home Electronics"; // Creator of the VESA standard
+
+ // Creator of the VESA standard
+ return "NEC Home Electronics";
}
/**
@@ -148,5 +120,5 @@ string VideoElectronicsStandardsAssociation::vendor_name() {
* @return The name of the device
*/
string VideoElectronicsStandardsAssociation::device_name() {
- return "VESA compatible graphics card";
+ return "VESA compatible graphics card";
}
diff --git a/kernel/src/drivers/video/vga.cpp b/kernel/src/drivers/video/vga.cpp
index a1831d08..0894866b 100644
--- a/kernel/src/drivers/video/vga.cpp
+++ b/kernel/src/drivers/video/vga.cpp
@@ -33,51 +33,49 @@ VideoGraphicsArray::~VideoGraphicsArray() = default;
*
* @param registers The VGA registers to write to.
*/
-void VideoGraphicsArray::write_registers(uint8_t* registers)
-{
- // Move to the next register
- m_misc_port.write(*(registers++));
-
- // Set the sequencer registers
- for (uint8_t i = 0; i < 5; i++ ) {
- m_sequence_index_port.write(i);
- m_sequence_data_port.write(*(registers++));
- }
-
- // Clear protection bit to enable writing to CR0-7
- m_crtc_index_port.write(0x03);
- crtc_data_port.write(crtc_data_port.read() | 0x80);
- m_crtc_index_port.write(0x11);
- crtc_data_port.write(crtc_data_port.read() | ~0x80);
-
- // Ensure protection bit is set
- registers[0x03] = registers[0x03] | 0x80;
- registers[0x11] = registers[0x11] & ~0x80;
-
- // write the CRTC registers
- for (uint8_t i = 0; i < 25; i++ ) {
- m_crtc_index_port.write(i);
- crtc_data_port.write(*(registers++));
- }
-
- // write the graphics controller registers
- for(uint8_t i = 0; i < 9; i++)
- {
- m_graphics_controller_index_port.write(i);
- m_graphics_controller_data_port.write(*(registers++));
- }
-
- // write the attribute controller registers
- for(uint8_t i = 0; i < 21; i++)
- {
- m_attribute_controller_reset_port.read();
- m_attribute_controller_index_port.write(i);
- m_attribute_controller_write_port.write(*(registers++));
- }
-
- // Re-Lock CRTC and unblank display
- m_attribute_controller_reset_port.read();
- m_attribute_controller_index_port.write(0x20);
+void VideoGraphicsArray::write_registers(uint8_t *registers) {
+
+ // Move to the next register
+ m_misc_port.write(*(registers++));
+
+ // Set the sequencer registers
+ for (uint8_t i = 0; i < 5; i++) {
+ m_sequence_index_port.write(i);
+ m_sequence_data_port.write(*(registers++));
+ }
+
+ // Clear protection bit to enable writing to CR0-7
+ m_crtc_index_port.write(0x03);
+ crtc_data_port.write(crtc_data_port.read() | 0x80);
+ m_crtc_index_port.write(0x11);
+ crtc_data_port.write(crtc_data_port.read() | ~0x80);
+
+ // Ensure protection bit is set
+ registers[0x03] = registers[0x03] | 0x80;
+ registers[0x11] = registers[0x11] & ~0x80;
+
+ // Write the CRTC registers
+ for (uint8_t i = 0; i < 25; i++) {
+ m_crtc_index_port.write(i);
+ crtc_data_port.write(*(registers++));
+ }
+
+ // Write the graphics controller registers
+ for (uint8_t i = 0; i < 9; i++) {
+ m_graphics_controller_index_port.write(i);
+ m_graphics_controller_data_port.write(*(registers++));
+ }
+
+ // Write the attribute controller registers
+ for (uint8_t i = 0; i < 21; i++) {
+ m_attribute_controller_reset_port.read();
+ m_attribute_controller_index_port.write(i);
+ m_attribute_controller_write_port.write(*(registers++));
+ }
+
+ // Re-Lock CRTC and unblank display
+ m_attribute_controller_reset_port.read();
+ m_attribute_controller_index_port.write(0x20);
}
@@ -86,9 +84,8 @@ void VideoGraphicsArray::write_registers(uint8_t* registers)
*
* @return True if the specified resolution is supported, otherwise false.
*/
-bool VideoGraphicsArray::supports_mode(uint32_t width, uint32_t height, uint32_t colour_depth)
-{
- return width == 320 && height == 200 && colour_depth == 8;
+bool VideoGraphicsArray::supports_mode(uint32_t width, uint32_t height, uint32_t colour_depth) {
+ return width == 320 && height == 200 && colour_depth == 8;
}
/**
@@ -100,34 +97,31 @@ bool VideoGraphicsArray::supports_mode(uint32_t width, uint32_t height, uint32_t
*
* @return True if the card was able to set the resolution, otherwise false.
*/
-bool VideoGraphicsArray::internal_set_mode(uint32_t width, uint32_t height, uint32_t colour_depth)
-{
- if(!supports_mode(width, height, colour_depth))
- return false;
-
- //Values from osdev / modes.c
- unsigned char g_320x200x256[] =
- {
- // MISC
- 0x63,
- // SEQ
- 0x03, 0x01, 0x0F, 0x00, 0x0E,
- // CRTC
- 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
- 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
- 0xFF,
- // GC
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
- 0xFF,
- // AC
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- 0x41, 0x00, 0x0F, 0x00, 0x00
- };
-
- write_registers(g_320x200x256);
- return true;
+bool VideoGraphicsArray::internal_set_mode(uint32_t width, uint32_t height, uint32_t colour_depth) {
+
+ //Values from osdev / modes.c
+ unsigned char g_320x200x256[] =
+ {
+ // MISC
+ 0x63,
+ // SEQ
+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
+ // CRTC
+ 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
+ 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
+ 0xFF,
+ // GC
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ // AC
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00
+ };
+
+ write_registers(g_320x200x256);
+ return true;
}
/**
@@ -135,27 +129,29 @@ bool VideoGraphicsArray::internal_set_mode(uint32_t width, uint32_t height, uint
*
* @return The framebuffer address.
*/
-uint8_t* VideoGraphicsArray::get_frame_buffer_segment()
-{
-
- // Optimise so that don't have to read and write to the port every time
- return (uint8_t*)0xA0000;
-
- //read data from index number 6
- m_graphics_controller_index_port.write(0x06);
- uint8_t segmentNumber =
- m_graphics_controller_data_port.read() & (3<<2); //Shift by 2 as only interested in bits 3 & 4 (& 3 so all the other bits are removed)
- switch(segmentNumber)
- {
- default:
- case 0<<2: return (uint8_t*)nullptr;
- case 1<<2: return (uint8_t*)0xA0000;
- case 2<<2: return (uint8_t*)0xB0000;
- case 3<<2: return (uint8_t*)0xB8000;
- }
+uint8_t *VideoGraphicsArray::get_frame_buffer_segment() {
+
+ // Optimise so that don't have to read and write to the port every time
+ return (uint8_t *) 0xA0000;
+
+ //read data from index number 6
+ m_graphics_controller_index_port.write(0x06);
+ uint8_t segmentNumber =
+ m_graphics_controller_data_port.read() &
+ (3 << 2); //Shift by 2 as only interested in bits 3 & 4 (& 3 so all the other bits are removed)
+ switch (segmentNumber) {
+ default:
+ case 0 << 2:
+ return (uint8_t *) nullptr;
+ case 1 << 2:
+ return (uint8_t *) 0xA0000;
+ case 2 << 2:
+ return (uint8_t *) 0xB0000;
+ case 3 << 2:
+ return (uint8_t *) 0xB8000;
+ }
}
-
/**
* @brief Puts a 8 bit pixel on the screen.
*
@@ -163,13 +159,10 @@ uint8_t* VideoGraphicsArray::get_frame_buffer_segment()
* @param y The y coordinate of the pixel.
* @param colour The colour of the pixel.
*/
-void VideoGraphicsArray::render_pixel_8_bit(uint32_t x, uint32_t y, uint8_t colour){
-
- // Get the address of the pixel
- uint8_t*pixel_address = get_frame_buffer_segment() + 320*y + x;
+void VideoGraphicsArray::render_pixel_8_bit(uint32_t x, uint32_t y, uint8_t colour) {
- // Set the pixel
- *pixel_address = colour;
+ uint8_t *pixel_address = get_frame_buffer_segment() + 320 * y + x;
+ *pixel_address = colour;
}
/**
@@ -181,11 +174,8 @@ void VideoGraphicsArray::render_pixel_8_bit(uint32_t x, uint32_t y, uint8_t colo
*/
uint8_t VideoGraphicsArray::get_rendered_pixel_8_bit(uint32_t x, uint32_t y) {
- // Get the address of the pixel
- uint8_t*pixel_address = get_frame_buffer_segment() + 320*y + x;
-
- // Return the pixel
- return *pixel_address;
+ uint8_t *pixel_address = get_frame_buffer_segment() + 320 * y + x;
+ return *pixel_address;
}
/**
@@ -194,7 +184,9 @@ uint8_t VideoGraphicsArray::get_rendered_pixel_8_bit(uint32_t x, uint32_t y) {
* @return The name of the vendor.
*/
string VideoGraphicsArray::vendor_name() {
- return "IBM"; // VGA was made by IBM
+
+ // VGA was made by IBM
+ return "IBM";
}
/**
@@ -203,5 +195,5 @@ string VideoGraphicsArray::vendor_name() {
* @return The name of the device.
*/
string VideoGraphicsArray::device_name() {
- return "VGA compatible graphics card";
+ return "VGA compatible graphics card";
}
\ No newline at end of file
diff --git a/kernel/src/drivers/video/video.cpp b/kernel/src/drivers/video/video.cpp
index e9dece67..7b805130 100644
--- a/kernel/src/drivers/video/video.cpp
+++ b/kernel/src/drivers/video/video.cpp
@@ -7,13 +7,7 @@
using namespace MaxOS::drivers::video;
using namespace MaxOS::common;
-
-VideoDriver::VideoDriver()
-: Driver(),
- GraphicsContext()
-{
-
-}
+VideoDriver::VideoDriver() = default;
VideoDriver::~VideoDriver() = default;
@@ -51,19 +45,17 @@ bool VideoDriver::supports_mode(uint32_t, uint32_t, uint32_t) {
*/
bool VideoDriver::set_mode(uint32_t width, uint32_t height, uint32_t colorDepth) {
- // Check if the mode is supported
+ // Cant set it if not supported
if(!supports_mode(width, height, colorDepth))
return false;
- // Set the mode
- if(internal_set_mode(width, height, colorDepth))
- {
- this -> m_width = width;
- this -> m_height = height;
- this -> m_color_depth = colorDepth;
- return true;
- }
+ // Try set the mode
+ if(!internal_set_mode(width, height, colorDepth))
+ return false;
- // If setting the mode failed, return false
- return false;
+ // Store the mode
+ m_width = width;
+ m_height = height;
+ m_color_depth = colorDepth;
+ return true;
}
\ No newline at end of file
diff --git a/kernel/src/filesystem/fat32.cpp b/kernel/src/filesystem/fat32.cpp
deleted file mode 100644
index 40d4dc97..00000000
--- a/kernel/src/filesystem/fat32.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-//
-// Created by 98max on 1/01/2023.
-//
-
-#include
-
-using namespace MaxOS;
-using namespace MaxOS::common;
-using namespace MaxOS::drivers;
-using namespace MaxOS::filesystem;
-using namespace MaxOS::memory;
diff --git a/kernel/src/filesystem/filesystem.cpp b/kernel/src/filesystem/filesystem.cpp
index 44defcc4..d7c2c075 100644
--- a/kernel/src/filesystem/filesystem.cpp
+++ b/kernel/src/filesystem/filesystem.cpp
@@ -3,7 +3,343 @@
//
#include
+#include
using namespace MaxOS;
using namespace MaxOS::filesystem;
+using namespace MaxOS::common;
+File::File() = default;
+
+File::~File() = default;
+
+/**
+ * @brief Write data to the file
+ *
+ * @param data The byte buffer to write
+ * @param size The amount of data to write
+ */
+void File::write(const common::buffer_t* data, size_t amount) {
+}
+
+/**
+ * @brief Read data from the file
+ *
+ * @param data The byte buffer to read into
+ * @param size The amount of data to read
+ */
+void File::read(common::buffer_t* data, size_t amount) {
+}
+
+/**
+ * @brief Flush the file to the disk
+ */
+void File::flush() {
+}
+
+/**
+ * @brief Seek to a position in the file
+ *
+ * @param seek_type The type of seek to perform (where to seek to)
+ * @param offset The amount to seek
+ */
+void File::seek(SeekType seek_type, size_t offset) {
+
+ // Seek based on the type
+ switch (seek_type) {
+ case SeekType::SET:
+ m_offset = offset;
+ break;
+
+ case SeekType::CURRENT:
+ m_offset += offset;
+ break;
+
+ case SeekType::END:
+ m_offset = size() - offset;
+ break;
+ }
+}
+
+/**
+ * @brief Get where the file is currently at (amount read/write/seeked)
+ *
+ * @return The current position in the file
+ */
+uint32_t File::position() {
+ return m_offset;
+}
+
+/**
+ * @brief Get the name of the file
+ *
+ * @return The name of the file
+ */
+string File::name() {
+ return m_name;
+}
+
+/**
+ * @brief Get the size of the file
+ *
+ * @return The size of the file (in bytes)
+ */
+size_t File::size() {
+ return m_size;
+}
+
+Directory::Directory() = default;
+
+Directory::~Directory() {
+
+ // Free the files
+ for (auto &file: m_files)
+ delete file;
+
+ // Free the subdirectories
+ for (auto &subdirectory: m_subdirectories)
+ delete subdirectory;
+
+}
+
+/**
+ * @brief Read the directory from the disk
+ */
+void Directory::read_from_disk() {
+
+}
+
+/**
+ * @brief Get the files in the directory
+ *
+ * @return A list of all the files in the directory
+ */
+common::Vector Directory::files() {
+ return m_files;
+}
+
+/**
+ * @brief Open a file in the directory
+ *
+ * @param name The name of the file to open
+ * @return
+ */
+File* Directory::open_file(const string &name) {
+
+ // Try to find the file
+ for (auto &file: m_files)
+ if (file->name() == name)
+ return file;
+
+ // File not found
+ return nullptr;
+}
+
+/**
+ * @brief Create a file in the directory
+ *
+ * @param name The name of the file to create
+ * @return A new file object or null if it could not be created
+ */
+File* Directory::create_file(const string &name) {
+ return nullptr;
+}
+
+/**
+ * @brief Delete a file in the directory
+ *
+ * @param name The name of the file to remove
+ */
+void Directory::remove_file(const string &name) {
+}
+
+/**
+ * @brief Get the subdirectories in the directory
+ *
+ * @return The subdirectories in the directory
+ */
+common::Vector Directory::subdirectories() {
+ return m_subdirectories;
+}
+
+/**
+ * @brief Open a directory in the directory
+ *
+ * @param name The name of the directory to open
+ * @return The directory object or null if it could not be opened
+ */
+Directory* Directory::open_subdirectory(const string &name) {
+
+ // Try to find the directory
+ for (auto &subdirectory: m_subdirectories)
+ if (subdirectory->name() == name) {
+ subdirectory->read_from_disk();
+ return subdirectory;
+ }
+
+ // Directory not found
+ return nullptr;
+}
+
+/**
+ * @brief Create a directory in the directory
+ *
+ * @param name The name of the directory to create
+ * @return The new directory object or null if it could not be created
+ */
+Directory* Directory::create_subdirectory(const string &name) {
+ return nullptr;
+}
+
+/**
+ * @brief Try to remove a directory in the directory
+ * @param name The name of the directory to remove
+ */
+void Directory::remove_subdirectory(const string &name) {
+}
+
+
+/**
+ * @brief Get the name of the directory
+ *
+ * @return The name of the directory
+ */
+string Directory::name() {
+ return m_name;
+}
+
+/**
+ * @brief Get the size of the directory
+ *
+ * @return The size of the directory (sum of all the files in bytes)
+ */
+size_t Directory::size() {
+
+ // Sum the size of all the files
+ size_t size = 0;
+ for (auto &file: m_files)
+ size += file->size();
+
+ return size;
+
+}
+
+/**
+ * @brief Rename a file in the directory
+ *
+ * @param file The file to rename
+ * @param new_name The new name of the file
+ */
+void Directory::rename_file(File* file, string const &new_name) {
+
+ rename_file(file->name(), new_name);
+
+}
+
+/**
+ * @brief Rename a file in the directory
+ *
+ * @param old_name The file to rename
+ * @param new_name The new name of the file
+ */
+void Directory::rename_file(string const &old_name, string const &new_name) {
+
+ ASSERT(false, "not implemented");
+
+}
+
+/**
+ * @brief Rename a subdirectory in the directory
+ *
+ * @param directory The directory to rename
+ * @param new_name The new name of the directory
+ */
+void Directory::rename_subdirectory(Directory* directory, string const &new_name) {
+
+ rename_subdirectory(directory->name(), new_name);
+
+}
+
+/**
+ * @brief Rename a subdirectory in the directory
+ *
+ * @param old_name The directory to rename
+ * @param new_name The new name of the directory
+ */
+void Directory::rename_subdirectory(string const &old_name, string const &new_name) {
+ ASSERT(false, "not implemented");
+}
+
+FileSystem::FileSystem() = default;
+
+FileSystem::~FileSystem() {
+
+ // Free the root directory
+ delete m_root_directory;
+
+};
+
+/**
+ * @brief Get the directory at "/"
+ *
+ * @return The root directory of the filesystem
+ */
+Directory* FileSystem::root_directory() {
+ return m_root_directory;
+}
+
+/**
+ * @brief Get the directory at a given path
+ *
+ * @param path The path to the directory
+ * @return The directory object or null if it could not be opened
+ */
+Directory* FileSystem::get_directory(const string &path) {
+
+ // Check if the path is the root
+ if (path == "/")
+ return root_directory();
+
+ // Recursively open the directory
+ Directory* directory = root_directory();
+ string directory_path = path;
+ while (directory_path.length() > 0) {
+
+ // Get the name of the directory
+ string directory_name = Path::top_directory(directory_path);
+
+ // Open the directory
+ Directory* subdirectory = directory->open_subdirectory(directory_name);
+ if (!subdirectory)
+ return nullptr;
+
+ // Set the new directory
+ directory = subdirectory;
+
+ // Get the path to the next directory
+ directory_path = directory_path.substring(directory_name.length() + 1, directory_path.length() - directory_name.length() - 1);
+ }
+
+ return directory;
+}
+
+/**
+ * @brief Check if a path exists on the filesystem
+ *
+ * @param path The path to check
+ * @return True if the path exists, false otherwise
+ */
+bool FileSystem::exists(const string &path) {
+
+ // Get the directory at the path
+ string directory_path = Path::file_path(path);
+ Directory* directory = get_directory(directory_path);
+
+ // Check if the directory exists
+ if (!directory)
+ return false;
+
+ // Check if the file exists
+ const string file_name = Path::file_name(path);
+ return directory->open_file(file_name) != nullptr;
+}
\ No newline at end of file
diff --git a/kernel/src/filesystem/format/ext2.cpp b/kernel/src/filesystem/format/ext2.cpp
new file mode 100644
index 00000000..409cc751
--- /dev/null
+++ b/kernel/src/filesystem/format/ext2.cpp
@@ -0,0 +1,1136 @@
+//
+// Created by 98max on 17/07/2025.
+//
+#include
+
+using namespace MaxOS;
+using namespace MaxOS::filesystem;
+using namespace MaxOS::common;
+using namespace MaxOS::filesystem::format;
+using namespace MaxOS::filesystem::format::ext2;
+using namespace MaxOS::drivers;
+using namespace MaxOS::drivers::disk;
+using namespace MaxOS::drivers::clock;
+
+Ext2Volume::Ext2Volume(drivers::disk::Disk *disk, lba_t partition_offset)
+: disk(disk),
+ partition_offset(partition_offset)
+{
+
+ // Read superblock
+ buffer_t superblock_buffer(&superblock, 1024);
+ disk->read(partition_offset + 2, &superblock_buffer, 512);
+ disk->read(partition_offset + 3, &superblock_buffer, 512);
+
+ // Validate signature
+ ASSERT(superblock.signature == 0xEF53, "Ext2 Filesystem doesnt have a valid signature\n");
+
+ // Version 0 has constant inode info
+ if (superblock.version_major < 1) {
+ superblock.first_inode = 11;
+ superblock.inode_size = 128;
+ }
+
+ // Parse the superblock
+ block_size = 1024 << superblock.block_size;
+ total_block_groups = (superblock.total_blocks + superblock.blocks_per_group - 1) / superblock.blocks_per_group;
+ block_group_descriptor_table_block = superblock.starting_block + 1;
+ block_group_descriptor_table_size = total_block_groups * sizeof(block_group_descriptor_t);
+ pointers_per_block = block_size / sizeof(uint32_t);
+ inodes_per_block = block_size / superblock.inode_size;
+ sectors_per_block = block_size / 512;
+ blocks_per_inode_table = (superblock.inode_size * superblock.inodes_per_group + (block_size - 1)) / block_size;
+ sectors_per_inode_table = (superblock.inode_size * superblock.inodes_per_group + (512 - 1)) / 512;
+
+ // Read the block groups
+ block_groups = new block_group_descriptor_t *[total_block_groups]{nullptr};
+ uint32_t bgdt_lba = partition_offset + block_group_descriptor_table_block * sectors_per_block;
+ uint32_t sectors_to_read = (block_group_descriptor_table_size + block_size - 1) / block_size * sectors_per_block;
+ buffer_t bg_buffer(sectors_to_read * 512);
+ for (uint32_t i = 0; i < sectors_to_read; ++i)
+ disk->read(bgdt_lba + i, &bg_buffer, 512);
+
+ // Store the block groups
+ for (uint32_t i = 0; i < total_block_groups; ++i) {
+ block_groups[i] = new block_group_descriptor_t;
+ memcpy(block_groups[i], bg_buffer.raw() + i * sizeof(block_group_descriptor_t), sizeof(block_group_descriptor_t));
+ }
+}
+
+Ext2Volume::~Ext2Volume() = default;
+
+/**
+ * @breif Write a single block from a buffer into onto the disk
+ *
+ * @param block_num The block to update
+ * @param buffer The buffer to read from
+ */
+void Ext2Volume::write_block(uint32_t block_num, buffer_t *buffer) {
+
+ // Ensure the buffer is in the right format
+ buffer->set_offset(0);
+ bool old = buffer->update_offset;
+ buffer->update_offset = true;
+
+ // Read each sector of the block
+ for (size_t i = 0; i < sectors_per_block; ++i)
+ disk->write(partition_offset + block_num * sectors_per_block + i, buffer, 512);
+
+ // Reset buffer
+ buffer->set_offset(0);
+ buffer->update_offset = old;
+};
+
+/**
+ * @brief Write an inode to the filesystem
+ *
+ * @param inode_num The inode index
+ * @param inode The inode to read from
+ */
+void Ext2Volume::write_inode(uint32_t inode_num, inode_t *inode) {
+
+ // Locate the inode
+ uint32_t group = (inode_num - 1) / superblock.inodes_per_group;
+ uint32_t index = (inode_num - 1) % superblock.inodes_per_group;
+
+ // Locate the block
+ uint32_t inode_table = block_groups[group]->inode_table_address;
+ uint32_t offset = index * superblock.inode_size;
+ uint32_t block = offset / block_size;
+ uint32_t in_block_offset = offset % block_size;
+
+ // Read the inode
+ buffer_t buffer(block_size);
+ read_block(inode_table + block, &buffer);
+ buffer.copy_from(inode, sizeof(inode_t), in_block_offset);
+
+ // Modify the block
+ write_block(inode_table + block, &buffer);
+}
+
+/**
+ * @breif Reads a single block from the disk into a buffer
+ *
+ * @param block_num The block to read
+ * @param buffer The buffer to read into
+ */
+void Ext2Volume::read_block(uint32_t block_num, buffer_t *buffer) const {
+
+ // Ensure the buffer is in the right format
+ buffer->set_offset(0);
+
+ // Read each sector of the block
+ for (size_t i = 0; i < sectors_per_block; ++i)
+ disk->read(partition_offset + block_num * sectors_per_block + i, buffer, 512);
+
+ // Reset buffer
+ buffer->set_offset(0);
+
+}
+
+/**
+ * @brief Read an inode from the filesystem
+ *
+ * @param inode_num The inode index
+ */
+inode_t Ext2Volume::read_inode(uint32_t inode_num) const {
+
+ inode_t inode;
+
+ // Locate the inode
+ uint32_t group = (inode_num - 1) / superblock.inodes_per_group;
+ uint32_t index = (inode_num - 1) % superblock.inodes_per_group;
+
+ // Locate the block
+ uint32_t inode_table = block_groups[group]->inode_table_address;
+ uint32_t offset = index * superblock.inode_size;
+ uint32_t block = offset / block_size;
+ uint32_t in_block_offset = offset % block_size;
+
+ // Read the block
+ buffer_t buffer(block_size);
+ read_block(inode_table + block, &buffer);
+
+ // Read the inode from the block
+ buffer.copy_to(&inode, sizeof(inode_t), in_block_offset);
+ return inode;
+}
+
+/**
+ * @brief Allocates a single block to be used by an inode
+ *
+ * @return The new block number or 0 if the allocation failed
+ */
+uint32_t Ext2Volume::allocate_block() {
+
+ return allocate_blocks(1)[0];
+}
+
+/**
+ * @brief Allocates a set of blocks to be used by an inode
+ *
+ * @param amount The amount of blocks to allocate
+ * @return A list of the allocated blocks or [0] if the allocation failed
+ */
+Vector Ext2Volume::allocate_blocks(uint32_t amount) {
+
+ // No blocks to allocate
+ if (!amount)
+ return {1, 0};
+
+ // Find the block group with enough free blocks
+ block_group_descriptor_t *block_group = block_groups[0];
+ for (uint32_t bg_index = 0; bg_index < total_block_groups; block_group = block_groups[++bg_index])
+ if (block_group->free_blocks >= amount)
+ return allocate_group_blocks(bg_index, amount);
+
+ // No block group can contain the block so split across multiple
+ Vector result{};
+ while (amount > 0) {
+
+ // Find the block group with most free blocks
+ block_group = block_groups[0];
+ uint32_t bg_index = 0;
+ for (; bg_index < total_block_groups; ++bg_index)
+ if (block_groups[bg_index]->free_blocks > block_group->free_blocks)
+ block_group = block_groups[bg_index];
+
+ // No space
+ if (block_group->free_blocks == 0)
+ return {1, 0};
+
+ // Allocate the remaining blocks
+ auto allocated = allocate_group_blocks(bg_index, 1);
+ amount -= allocated.size();
+ for (auto block: allocated)
+ result.push_back(block);
+ }
+
+ return result;
+}
+
+/**
+ * @brief Allocate a certain amount of blocks in a block group
+ *
+ * @param block_group The block group where the allocation is performed
+ * @param amount The amount of blocks to allocate
+ * @return The block numbers allocated
+ */
+common::Vector Ext2Volume::allocate_group_blocks(uint32_t block_group, uint32_t amount) {
+
+ // Ensure enough space
+ block_group_descriptor_t *descriptor = block_groups[block_group];
+ if (amount > descriptor->free_blocks)
+ return {1, 0};
+
+ // Prepare
+ Vector result{};
+ buffer_t zeros(block_size);
+ zeros.clear();
+
+ // Read bitmap
+ buffer_t bitmap(block_size);
+ read_block(descriptor->block_usage_bitmap, &bitmap);
+
+ // Allocate the blocks
+ for (uint32_t i = 0; i < superblock.blocks_per_group; ++i) {
+
+ // Block is already used
+ if ((bitmap.raw()[i / 8] & (1u << (i % 8))) != 0)
+ continue;
+
+ // Mark as used
+ descriptor->free_blocks--;
+ superblock.unallocated_blocks--;
+ bitmap.raw()[i / 8] |= (uint8_t) (1u << (i % 8));
+
+ // Zero out data
+ uint32_t block = block_group * superblock.blocks_per_group + superblock.starting_block + i;
+ write_block(block, &zeros);
+ result.push_back(block);
+
+ // All done
+ amount--;
+ if (!amount)
+ break;
+ }
+
+ // Save the changed metadata
+ write_block(descriptor->block_usage_bitmap, &bitmap);
+ write_back_block_groups();
+ write_back_superblock();
+
+ return result;
+}
+
+/**
+ * @brief Free a certain amount of blocks in a block group and zero's them out.
+ *
+ * @param block_group The block group where the blocks exist
+ * @param amount The amount of blocks to free
+ */
+void Ext2Volume::free_group_blocks(uint32_t block_group, uint32_t amount, uint32_t start) {
+
+ // Read bitmap
+ block_group_descriptor_t *descriptor = block_groups[block_group];
+ buffer_t bitmap(block_size);
+ read_block(descriptor->block_usage_bitmap, &bitmap);
+
+ // Convert start to be index based on the group instead of global
+ start -= (block_group * superblock.blocks_per_group + superblock.starting_block);
+
+ // Free the blocks
+ for (uint32_t i = start; i < start + amount; ++i) {
+
+ // Block is already free (shouldn't happen)
+ if ((bitmap.raw()[i / 8] & (1u << (i % 8))) == 0)
+ continue;
+
+ // Mark as free
+ descriptor->free_blocks++;
+ superblock.unallocated_blocks++;
+ bitmap.raw()[i / 8] &= ~(1u << (i % 8));
+
+ // TODO: Decide whether to zero out or not, my implementation zeros on allocation but idk about others
+ }
+
+ // Save the changed metadata
+ write_block(descriptor->block_usage_bitmap, &bitmap);
+ write_back_block_groups();
+ write_back_superblock();
+
+}
+
+
+/**
+ * @brief Save any changes of the block groups to the disk
+ */
+void Ext2Volume::write_back_block_groups() const {
+
+ // Locate the block groups
+ uint32_t bgdt_blocks = (block_group_descriptor_table_size + block_size - 1) / block_size;
+ uint32_t sectors_to_write = bgdt_blocks * sectors_per_block;
+ uint32_t bgdt_lba = partition_offset + block_group_descriptor_table_block * sectors_per_block;
+
+ // Copy the block groups into the buffer
+ buffer_t bg_buffer(sectors_to_write * 512);
+ for (uint32_t i = 0; i < total_block_groups; ++i)
+ bg_buffer.copy_from(block_groups[i], sizeof(block_group_descriptor_t));
+
+ // Write the buffer to disk
+ bg_buffer.set_offset(0);
+ for (uint32_t i = 0; i < sectors_to_write; ++i)
+ disk->write(bgdt_lba + i, &bg_buffer, 512);
+}
+
+/**
+ * @brief Save the in memory superblock to the disk
+ */
+void Ext2Volume::write_back_superblock() {
+
+ // Store superblock
+ buffer_t buffer(1024);
+ buffer.copy_from(&superblock, sizeof(superblock_t));
+ buffer.set_offset(0);
+
+ // Write to disk
+ disk->write(partition_offset + 2, &buffer, 512);
+ disk->write(partition_offset + 3, &buffer, 512);
+}
+
+/**
+ * @brief How many blocks are needed to contain a set amount of bytes
+ *
+ * @param bytes Bytes needed
+ * @return The blocks required
+ */
+uint32_t Ext2Volume::bytes_to_blocks(size_t bytes) const {
+ return (bytes + block_size - 1) / block_size;
+}
+
+/**
+ * @brief Allocates a new inode and sets the base metadata. Also allocates block 0 of the inode
+ *
+ * @param is_directory is the inode to be used for a directory
+ * @return The new inode
+ */
+uint32_t Ext2Volume::create_inode(bool is_directory) {
+
+ ext2_lock.lock();
+
+ // Find the block group with enough free inodes
+ block_group_descriptor_t *block_group = block_groups[0];
+ uint32_t bg_index = 0;
+ for (; bg_index < total_block_groups; block_group = block_groups[++bg_index])
+ if (block_group->free_inodes >= 1)
+ break;
+
+ // Read bitmap
+ buffer_t bitmap(block_size);
+ read_block(block_group->block_inode_bitmap, &bitmap);
+
+ // First group contains reserved inodes
+ uint32_t inode_index = 0;
+ if (bg_index == 0 && superblock.first_inode > 1)
+ inode_index = superblock.first_inode - 1;
+
+ // Find a free inode
+ for (; inode_index < superblock.inodes_per_group; ++inode_index) {
+
+ // Block is already used
+ if ((bitmap.raw()[inode_index / 8] & (1u << (inode_index % 8))) != 0)
+ continue;
+
+ // Mark as used
+ block_group->free_inodes--;
+ superblock.unallocated_inodes--;
+ bitmap.raw()[inode_index / 8] |= (uint8_t) (1u << (inode_index % 8));
+
+ break;
+ }
+
+ // Convert into the 1-based inode index in the group
+ inode_index += bg_index * superblock.inodes_per_group + 1;
+
+ // Save the changed metadata
+ write_block(block_group->block_inode_bitmap, &bitmap);
+ write_back_block_groups();
+ write_back_superblock();
+
+ // Create the inode
+ inode_t inode{};
+ inode.creation_time = time_to_epoch(Clock::active_clock()->get_time());
+ inode.last_modification_time = time_to_epoch(Clock::active_clock()->get_time());
+ inode.block_pointers[0] = allocate_block();
+ inode.hard_links = is_directory ? 2 : 1;
+ inode.type = ((uint16_t) (is_directory ? InodeType::DIRECTORY : InodeType::FILE) >> 12) & 0xF;
+ inode.permissions =
+ (uint16_t) (is_directory ? InodePermissionsDefaults::DIRECTORY : InodePermissionsDefaults::FILE) & 0x0FFF;
+ write_inode(inode_index, &inode);
+
+ ext2_lock.unlock();
+ return inode_index;
+}
+
+/**
+ * @brief Mark an inode as free. Note: does NOT unallocated the inodes blocks, use free_group_blocks().
+ * @see free_group_blocks
+ *
+ * @param inode The inode number to mark as free
+ */
+void Ext2Volume::free_inode(uint32_t inode) {
+
+ // Find the block group containing the inode
+ uint32_t bg_index = (inode - 1) / superblock.inodes_per_group;
+ block_group_descriptor_t *block_group = block_groups[bg_index];
+
+ // Read bitmap
+ buffer_t bitmap(block_size);
+ read_block(block_group->block_inode_bitmap, &bitmap);
+
+ // First group contains reserved inodes
+ uint32_t inode_index = (inode - 1) % superblock.inodes_per_group;
+ if (bg_index == 0 && (inode_index < (superblock.first_inode - 1)))
+ return;
+
+ // Mark as used
+ block_group->free_inodes++;
+ superblock.unallocated_inodes++;
+ bitmap.raw()[inode_index / 8] &= (uint8_t) ~(1u << (inode_index % 8));
+
+ // Save the changed metadata
+ write_block(block_group->block_inode_bitmap, &bitmap);
+ write_back_block_groups();
+ write_back_superblock();
+}
+
+/**
+ * @brief Frees a group of blocks. Preferably with adjacent blocks apearing next to each other but not enforced.
+ * @param blocks The blocks to free
+ */
+void Ext2Volume::free_blocks(const common::Vector &blocks) {
+
+ // No blocks to free
+ if (blocks.empty())
+ return;
+
+ uint32_t start = blocks[0];
+ uint32_t previous = start;
+ uint32_t amount = 1;
+
+ // Free each adjacent set of blocks
+ for (auto &block: blocks) {
+
+ // First is already accounted for
+ if (block == start)
+ continue;
+
+ // Is this block adjacent
+ if ((previous + 1) == block) {
+ previous = block;
+ amount += 1;
+ continue;
+ }
+
+ // Adjacent set has ended
+ uint32_t group = (start - superblock.starting_block) / superblock.blocks_per_group;
+ free_group_blocks(group, amount, start);
+
+ // Reset
+ start = block;
+ previous = start;
+ amount = 1;
+ }
+
+ // Account for the last set of blocks in the loop
+ uint32_t group = (start - superblock.starting_block) / superblock.blocks_per_group;
+ free_group_blocks(group, amount, start);
+}
+
+
+InodeHandler::InodeHandler(Ext2Volume *volume, uint32_t inode_index)
+: m_volume(volume),
+ inode_number(inode_index),
+ inode(m_volume->read_inode(inode_number))
+{
+
+ // Read the block pointers
+ for (uint32_t direct_pointer = 0; direct_pointer < 12; ++direct_pointer)
+ if (inode.block_pointers[direct_pointer])
+ block_cache.push_back(inode.block_pointers[direct_pointer]);
+
+ buffer_t buffer(m_volume->block_size);
+ parse_indirect(1, inode.l1_indirect, &buffer);
+ parse_indirect(2, inode.l2_indirect, &buffer);
+ parse_indirect(3, inode.l3_indirect, &buffer);
+}
+
+/**
+ * @brief Read the size upper and lower into a single size_t
+ * @return The size of the inode data (not the inode itself)
+ */
+size_t InodeHandler::size() const {
+ return ((size_t) inode.size_upper << 32) | (size_t) inode.size_lower;
+}
+
+/**
+ * @brief Store the size of the inode data. (does not write to disk)
+ * @param size The new size
+ */
+void InodeHandler::set_size(size_t size) {
+
+ inode.size_lower = (uint32_t) (size & 0xFFFFFFFFULL);
+ inode.size_upper = (uint32_t) (size >> 32);
+
+}
+
+/**
+ * @brief Caches the indirect layers block pointers
+ *
+ * @param level Recursion level
+ * @param block The block number to parse from
+ * @param buffer Buffer to read into
+ */
+void InodeHandler::parse_indirect(uint32_t level, uint32_t block, buffer_t *buffer) {
+
+ // Invalid
+ if (block == 0)
+ return;
+
+ // Read the block
+ m_volume->read_block(block, buffer);
+ auto *pointers = (uint32_t *) (buffer->raw());
+
+ // Parse the pointers
+ for (size_t i = 0; i < m_volume->pointers_per_block; ++i) {
+ uint32_t pointer = pointers[i];
+
+ // Invaild
+ if (pointer == 0)
+ break;
+
+ // Has indirect sub entries
+ if (level > 1) {
+ parse_indirect(level - 1, pointer, buffer);
+ continue;
+ }
+
+ // Parse the entry
+ block_cache.push_back(pointer);
+ }
+}
+
+/**
+ * @brief Writes the Cache to the indirect layer block pointers
+ *
+ * @param level Recursion level
+ * @param block The block number to parse from
+ * @param buffer Buffer to read into
+ * @param index Current entry to write
+ */
+void InodeHandler::write_indirect(uint32_t level, uint32_t &block, size_t &index) {
+
+ // Nothing left to write
+ size_t remaining = block_cache.size() - index;
+ if (remaining == 0 || index >= block_cache.size())
+ return;
+
+ // Level hasn't been set yet
+ if (block == 0)
+ block = m_volume->allocate_block();
+
+ // Allocate a local buffer for this recursion level
+ buffer_t buffer(m_volume->block_size);
+ buffer.clear();
+ auto *pointers = (uint32_t *) buffer.raw();
+
+ // Write the pointers
+ for (size_t i = 0; i < m_volume->pointers_per_block; ++i) {
+
+ // Invalid
+ if (index >= block_cache.size())
+ break;
+
+ // Has indirect
+ if (level > 1) {
+ write_indirect(level - 1, pointers[i], index);
+ continue;
+ }
+
+ // Save the pointer
+ pointers[i] = block_cache[index++];
+ }
+
+ m_volume->write_block(block, &buffer);
+}
+
+/**
+ * @brief Saves the blocks to both the cached array and on disk inode
+ *
+ * @param blocks The blocks to save
+ */
+void InodeHandler::store_blocks(Vector const &blocks) {
+
+ Logger::DEBUG() << "STORING BLOCKS\n";
+
+ // Store in cache
+ for (auto block: blocks)
+ block_cache.push_back(block);
+
+ // Direct blocks
+ for (uint32_t i = 0; i < 12; ++i)
+ inode.block_pointers[i] = i < block_cache.size() ? block_cache[i] : 0;
+
+ // No need to do any indirects
+ if (block_cache.size() < 12)
+ return;
+
+ // Setup Recursive blocks
+ size_t index = 12;
+
+ // Write the blocks
+ uint32_t indirect_blocks[3] = {inode.l1_indirect, inode.l2_indirect, inode.l3_indirect};
+ for (int i = 0; i < 3; ++i) {
+
+ // Have to use temp because of packed field
+ uint32_t temp = indirect_blocks[i];
+ write_indirect(i + 1, temp, index);
+ indirect_blocks[i] = temp;
+ }
+
+ // Save the new blocks
+ inode.l1_indirect = indirect_blocks[0];
+ inode.l2_indirect = indirect_blocks[1];
+ inode.l3_indirect = indirect_blocks[2];
+
+ // NOTE: Blocks get allocated when writing indirects. This is then saved later in the write() function
+}
+
+/**
+ * @brief Increase the size of the inode's storage capacity by allocating new blocks.
+ *
+ * @param amount The amount to grow to in bytes
+ * @return
+ */
+size_t InodeHandler::grow(size_t amount, bool flush) {
+
+ // Nothing to grow
+ if (amount <= 0)
+ return size();
+
+ // Allocate new blocks
+ auto blocks = m_volume->allocate_blocks(m_volume->bytes_to_blocks(amount));
+ ASSERT(blocks[0] != 0, "Failed to allocate new blocks for file");
+
+ // Save the changes
+ store_blocks(blocks);
+ set_size(size() + amount);
+ if (flush)
+ save();
+
+ return size() + amount;
+}
+
+/**
+ * @brief Writes the inode meta data to disk
+ */
+void InodeHandler::save() {
+
+ m_volume->write_inode(inode_number, &inode);
+}
+
+/**
+ * @brief Marks this inode's blocks as free and then the inode as free
+ */
+void InodeHandler::free() {
+
+ m_volume->ext2_lock.lock();
+
+ // Free the inode
+ m_volume->free_blocks(block_cache);
+ m_volume->free_inode(inode_number);
+
+ m_volume->ext2_lock.unlock();
+}
+
+InodeHandler::~InodeHandler() = default;
+
+Ext2File::Ext2File(Ext2Volume *volume, uint32_t inode, string const &name)
+: m_volume(volume),
+ m_inode(volume, inode)
+{
+
+ // Set up the base information
+ m_name = name;
+ m_size = m_inode.size();
+
+}
+
+/**
+ * @brief Write data to the file (at the current seek position, updated to be += amount)
+ *
+ * @param data The byte buffer to write
+ * @param amount The amount of data to write
+ */
+void Ext2File::write(buffer_t const *data, size_t amount) {
+
+ // Nothing to write
+ if (amount == 0)
+ return;
+
+ // Prepare for writing
+ m_volume->ext2_lock.lock();
+ const uint32_t block_size = m_volume->block_size;
+ buffer_t buffer(block_size);
+
+ // Expand the file
+ if (m_offset + amount > m_size)
+ m_size = m_inode.grow((m_offset + amount) - m_size, false);
+
+ // Save the updated metadata
+ m_inode.inode.last_modification_time = time_to_epoch(Clock::active_clock()->get_time());
+ m_inode.save();
+
+ // Convert bytes to blocks
+ uint32_t block_start = m_offset / block_size;
+ uint32_t block_offset = m_offset % block_size;
+
+ // Write each block
+ size_t current_block = block_start;
+ size_t written = 0;
+ while (written < amount) {
+
+ // Read the block
+ uint32_t block = m_inode.block_cache[current_block++];
+ m_volume->read_block(block, &buffer);
+
+ // Where in this block to start writing
+ size_t buffer_start = (current_block - 1 == block_start) ? block_offset : 0;
+ size_t writable = (amount - written < block_size - buffer_start) ? (amount - written) : (block_size -
+ buffer_start);
+
+ // Update the block
+ buffer.copy_from(data, writable, buffer_start, written);
+ m_volume->write_block(block, &buffer);
+ written += writable;
+ }
+
+ // Clean up
+ m_offset += amount;
+ m_volume->ext2_lock.unlock();
+}
+
+/**
+* @brief Read data from the file (at the current seek position, updated to be += amount)
+*
+* @param data The byte buffer to read into
+* @param amount The amount of data to read
+*/
+void Ext2File::read(buffer_t *data, size_t amount) {
+
+ // Nothing to read
+ if (m_size == 0 || amount == 0)
+ return;
+
+ // Prepare for reading
+ m_volume->ext2_lock.lock();
+ const uint32_t block_size = m_volume->block_size;
+ buffer_t buffer(block_size);
+
+ // Force bounds
+ if (m_offset + amount > m_size)
+ amount = m_size - m_offset;
+
+ // Convert bytes to blocks
+ uint32_t block_start = m_offset / block_size;
+ uint32_t block_offset = m_offset % block_size;
+
+ // Read each block
+ size_t current_block = block_start;
+ size_t read = 0;
+ while (read < amount) {
+
+ // Read the block
+ uint32_t block = m_inode.block_cache[current_block++];
+ m_volume->read_block(block, &buffer);
+
+ // Where in this block to start reading
+ size_t buffer_start = (current_block - 1 == block_start) ? block_offset : 0;
+ size_t readable = (amount - read < block_size - buffer_start) ? (amount - read) : (block_size - buffer_start);
+
+ // Read the block
+ buffer.copy_to(data, readable, buffer_start, read);
+ read += readable;
+
+ }
+
+ // Clean up
+ m_offset += amount;
+ m_volume->ext2_lock.unlock();
+}
+
+/**
+ * @brief Flush the file to the disk
+ */
+void Ext2File::flush() {
+ File::flush();
+}
+
+Ext2File::~Ext2File() = default;
+
+Ext2Directory::Ext2Directory(Ext2Volume *volume, uint32_t inode, const string &name)
+: m_volume(volume),
+ m_inode(m_volume, inode)
+{
+ m_name = name;
+}
+
+/**
+ * @brief Store all entries from a buffer and convert to File or Directory objects
+ */
+void Ext2Directory::parse_block(buffer_t *buffer) {
+
+ size_t offset = 0;
+ while (offset < m_volume->block_size) {
+
+ // Read the entry
+ auto *entry = (directory_entry_t *) (buffer->raw() + offset);
+ m_entries.push_back(*entry);
+
+ // Not valid
+ if (entry->inode == 0 || entry->name_length == 0)
+ break;
+
+ // Parse
+ string filename(buffer->raw() + offset + sizeof(directory_entry_t), entry->name_length);
+ m_entry_names.push_back(filename);
+ uint32_t inode = entry->inode;
+
+ // Create the object
+ switch ((EntryType) entry->type) {
+
+ case EntryType::FILE:
+ m_files.push_back(new Ext2File(m_volume, inode, filename));
+ break;
+
+ case EntryType::DIRECTORY:
+ m_subdirectories.push_back(new Ext2Directory(m_volume, inode, filename));
+ break;
+
+ default:
+ Logger::WARNING() << "Unknown entry type: " << entry->type << "\n";
+
+ }
+
+ // Go to next
+ offset += entry->size;
+ }
+}
+
+/**
+ * @brief Removes an entry reference from the directory
+ *
+ * @param name The name of the entry to remove
+ * @param is_directory Is the entry expected to be a directory (otherwise assumed to be a file)
+ * @param clear Should the inode be freed and the data blocks unallocated
+ */
+void Ext2Directory::remove_entry(string const &name, bool is_directory, bool clear) {
+
+ // Find the entry
+ uint32_t index = 0;
+ directory_entry_t *entry = nullptr;
+ for (; index < m_entries.size(); ++index)
+ if (m_entry_names[index] == name) {
+ entry = &m_entries[index];
+ break;
+ }
+
+ // No entry found
+ if (!entry || entry->type != (uint8_t) (is_directory ? EntryType::DIRECTORY : EntryType::FILE))
+ return;
+
+ // Clear the inode
+ if (clear) {
+ InodeHandler inode(m_volume, entry->inode);
+ inode.free();
+ }
+
+ // Remove the reference from this directory
+ m_entries.erase(entry);
+ m_entry_names.erase(m_entry_names.begin() + index);
+ write_entries();
+}
+
+/**
+ * @brief Rename a directory entry and save it to disk
+ *
+ * @param old_name The current name of the entry
+ * @param new_name The name to change it to
+ * @param is_directory Search for entries with the type DIRECTORY (otherwise assume FILE)
+ */
+void Ext2Directory::rename_entry(string const &old_name, string const &new_name, bool is_directory) {
+
+ // Change the name
+ for (int i = 0; i < m_entry_names.size(); ++i)
+ if (m_entry_names[i] == old_name &&
+ m_entries[i].type == (uint8_t) (is_directory ? EntryType::DIRECTORY : EntryType::FILE))
+ m_entry_names[i] = new_name;
+
+ // Save the change
+ write_entries();
+
+}
+
+/**
+ * @brief Read the directory from the inode on the disk
+ */
+void Ext2Directory::read_from_disk() {
+
+ m_volume->ext2_lock.lock();
+ m_entries.clear();
+ m_entry_names.clear();
+
+ // Clear the old files & Directories
+ for (auto &file: m_files)
+ delete file;
+ m_files.clear();
+
+ for (auto &directory: m_subdirectories)
+ delete directory;
+ m_subdirectories.clear();
+
+ // Read the direct blocks (cant use for( : ))
+ buffer_t buffer(m_volume->block_size);
+ for (int i = 0; i < m_inode.block_cache.size(); ++i) {
+ uint32_t block_pointer = m_inode.block_cache[i];
+
+ // Invalid block
+ if (block_pointer == 0)
+ break;
+
+ // Parse the block
+ m_volume->read_block(block_pointer, &buffer);
+ parse_block(&buffer);
+ }
+
+ m_volume->ext2_lock.unlock();
+}
+
+void Ext2Directory::write_entries() {
+
+ // Calculate the size needed to store the entries and the null entry
+ size_t size_required = sizeof(directory_entry_t);
+ for (int i = 0; i < m_entries.size(); ++i) {
+ size_t size = sizeof(directory_entry_t) + m_entry_names[i].length() + 1;
+ size += (size % 4) ? 4 - size % 4 : 0;
+ size_required += size;
+ }
+
+ // Expand the directory
+ size_t blocks_required = m_volume->bytes_to_blocks(size_required);
+ if (blocks_required > m_inode.block_cache.size())
+ m_inode.grow((blocks_required - m_inode.block_cache.size()) * m_volume->block_size, false);
+
+ // Prepare for writing
+ m_volume->ext2_lock.lock();
+ const uint32_t block_size = m_volume->block_size;
+ buffer_t buffer(block_size, false);
+ buffer.clear();
+
+ // Save the updated metadata
+ m_inode.set_size(blocks_required * block_size);
+ m_inode.inode.last_modification_time = time_to_epoch(Clock::active_clock()->get_time());
+ m_inode.save();
+
+ // Write each entry
+ size_t current_block = 0;
+ size_t buffer_offset = 0;
+ for (int i = 0; i < m_entries.size(); ++i) {
+
+ // Get the current entry
+ directory_entry_t &entry = m_entries[i];
+ char *name = m_entry_names[i].c_str();
+
+ // Update the size
+ entry.name_length = m_entry_names[i].length();
+ entry.size = sizeof(directory_entry_t) + entry.name_length + 1;
+ entry.size += (entry.size % 4) ? 4 - (entry.size % 4) : 0;
+
+ // Entry needs to be stored in the next block
+ if (entry.size + buffer_offset > block_size) {
+ m_volume->write_block(m_inode.block_cache[current_block], &buffer);
+ buffer.clear();
+ current_block++;
+ buffer_offset = 0;
+ }
+
+ // If it is the last entry it takes up the rest of the block
+ if (i == m_entries.size() - 1)
+ entry.size = block_size - buffer_offset;
+
+ // Copy the entry and the name
+ buffer.copy_from(&entry, sizeof(entry), buffer_offset);
+ buffer.copy_from(name, entry.name_length + 1, buffer_offset + sizeof(entry));
+ buffer_offset += entry.size;
+ }
+
+ // Save the last block
+ m_volume->write_block(m_inode.block_cache[current_block], &buffer);
+
+ // Clean up
+ m_volume->ext2_lock.unlock();
+}
+
+directory_entry_t Ext2Directory::create_entry(const string &name, uint32_t inode, bool is_directory) {
+
+ // Create the inode
+ directory_entry_t entry{};
+ entry.inode = inode ? inode : m_volume->create_inode(is_directory);
+ entry.type = (uint32_t) (is_directory ? EntryType::DIRECTORY : EntryType::FILE);
+ entry.name_length = name.length();
+ entry.size = sizeof(entry) + entry.name_length;
+ entry.size += entry.size % 4 ? 4 - entry.size % 4 : 0;
+
+ // Save the inode
+ m_entries.push_back(entry);
+ m_entry_names.push_back(name);
+ write_entries();
+
+ return entry;
+}
+
+/**
+ * @brief Create a new file in the directory
+ *
+ * @param name The name of the file to create
+ * @return The new file object or null if it could not be created
+ */
+File *Ext2Directory::create_file(string const &name) {
+
+ // Check if the file already exists
+ for (auto &file: m_files)
+ if (file->name() == name)
+ return nullptr;
+
+ // Create the file
+ auto file = new Ext2File(m_volume, create_entry(name, 0, false).inode, name);
+ m_files.push_back(file);
+ return file;
+}
+
+/**
+ * @brief Delete a file from this directory
+ *
+ * @param name The name of the file to delete
+ */
+void Ext2Directory::remove_file(string const &name) {
+ remove_entry(name, false);
+}
+
+/**
+ * @brief Renames the file from the old name to the new name if it exists
+ *
+ * @param old_name The current name of the file that is to be changed
+ * @param new_name What the new name should be
+ */
+void Ext2Directory::rename_file(string const &old_name, string const &new_name) {
+ rename_entry(old_name, new_name, false);
+}
+
+/**
+ * @brief Create a new directory in the directory
+ *
+ * @param name The name of the directory to create
+ * @return The new directory object or null if it could not be created
+ */
+Directory *Ext2Directory::create_subdirectory(string const &name) {
+
+ // Check if the directory already exists
+ for (auto &subdirectory: m_subdirectories)
+ if (subdirectory->name() == name)
+ return nullptr;
+
+ // Store the directory
+ auto directory = new Ext2Directory(m_volume, create_entry(name, 0, true).inode, name);
+ m_subdirectories.push_back(directory);
+
+ // Create self & parent references
+ directory->create_entry(".", directory->m_inode.inode_number, true);
+ directory->create_entry("..", m_inode.inode_number, true);
+
+ return directory;
+}
+
+/**
+ * @brief Remove a directory entry from the directory
+ *
+ * @param name The name of the entry to remove
+ */
+void Ext2Directory::remove_subdirectory(string const &name) {
+ remove_entry(name, true);
+}
+
+/**
+ * @brief Renames the directory from the old name to the new name if it exists
+ *
+ * @param old_name The current name of the directory that is to be changed
+ * @param new_name What the new name should be
+ */
+void Ext2Directory::rename_subdirectory(string const &old_name, string const &new_name) {
+ rename_entry(old_name, new_name, true);
+}
+
+Ext2Directory::~Ext2Directory() = default;
+
+Ext2FileSystem::Ext2FileSystem(Disk *disk, uint32_t partition_offset)
+ : m_volume(disk, partition_offset) {
+
+ // Create the root directory
+ m_root_directory = new Ext2Directory(&m_volume, 2, "/");
+ m_root_directory->read_from_disk();
+
+}
+
+Ext2FileSystem::~Ext2FileSystem() {
+ delete m_root_directory;
+};
\ No newline at end of file
diff --git a/kernel/src/filesystem/format/fat32.cpp b/kernel/src/filesystem/format/fat32.cpp
new file mode 100644
index 00000000..381f77f3
--- /dev/null
+++ b/kernel/src/filesystem/format/fat32.cpp
@@ -0,0 +1,965 @@
+//
+// Created by 98max on 1/01/2023.
+//
+
+#include
+#include
+
+using namespace MaxOS;
+using namespace MaxOS::common;
+using namespace MaxOS::drivers;
+using namespace MaxOS::drivers::disk;
+using namespace MaxOS::filesystem;
+using namespace MaxOS::filesystem::format;
+using namespace MaxOS::memory;
+
+Fat32Volume::Fat32Volume(Disk *hd, uint32_t partition_offset)
+: disk(hd)
+{
+
+ // Read the BIOS parameter block
+ buffer_t bpb_buffer(&bpb, sizeof(bpb32_t));
+ disk->read(partition_offset, &bpb_buffer);
+
+ // Parse the FAT info
+ uint32_t total_data_sectors = bpb.total_sectors_32 - (bpb.reserved_sectors + (bpb.table_copies * bpb.table_size_32));
+ fat_total_clusters = total_data_sectors / bpb.sectors_per_cluster;
+ fat_lba = partition_offset + bpb.reserved_sectors;
+ fat_copies = bpb.table_copies;
+ fat_info_lba = partition_offset + bpb.fat_info;
+ data_lba = fat_lba + (bpb.table_copies * bpb.table_size_32);
+ root_lba = data_lba + bpb.sectors_per_cluster * (bpb.root_cluster - 2);
+
+ // Read the fs info
+ buffer_t fs_buffer(&fsinfo, sizeof(fs_info_t));
+ disk->read(fat_info_lba, &fs_buffer);
+
+ // Validate the fat information
+ if (fsinfo.lead_signature != 0x41615252 || fsinfo.structure_signature != 0x61417272 ||
+ fsinfo.trail_signature != 0xAA550000) {
+ Logger::ERROR() << "Invalid FAT32 filesystem information TODO: Handle this\n";
+ return;
+ }
+}
+
+Fat32Volume::~Fat32Volume() = default;
+
+/**
+ * @brief Take the cluster and gets the next cluster in the chain
+ *
+ * @param cluster The base cluster to start from
+ * @return The next cluster in the chain
+ */
+lba_t Fat32Volume::next_cluster(lba_t cluster) {
+
+ // Get the location in the FAT table
+ lba_t offset = cluster * sizeof(uint32_t);
+ lba_t sector = fat_lba + (offset / bpb.bytes_per_sector);
+ uint32_t entry_index = offset % bpb.bytes_per_sector;
+
+ // Read the FAT entry
+ buffer_t fat(bpb.bytes_per_sector);
+ disk->read(sector, &fat);
+
+ // Get the next cluster info (mask the upper 4 bits)
+ auto entry = (uint32_t *) (&(fat.raw()[entry_index])); // TODO & here is weird
+ return *entry & 0x0FFFFFFF;
+}
+
+/**
+ * @brief Sets the next cluster in the chain (where the base cluster should point)
+ *
+ * @param cluster The base cluster to start from
+ * @param next_cluster The next cluster in the chain
+ * @return The next cluster in the chain
+ */
+uint32_t Fat32Volume::set_next_cluster(uint32_t cluster, uint32_t next_cluster) {
+
+ // TODO - when in userspace: For performance cache fat entirely, cache file data, cache cluster chains
+
+ // Get the location in the FAT table
+ lba_t offset = cluster * sizeof(uint32_t);
+
+ for (int i = 0; i < fat_copies; ++i) {
+
+ lba_t sector = (fat_lba + i * bpb.table_size_32) + (offset / bpb.bytes_per_sector);
+ uint32_t entry_index = offset % bpb.bytes_per_sector;
+
+ // Read the FAT entry
+ buffer_t fat(bpb.bytes_per_sector);
+ disk->read(sector, &fat);
+
+ // Set the next cluster info (mask the upper 4 bits)
+ auto entry = (uint32_t *) (&(fat.raw()[entry_index]));
+ *entry = next_cluster & 0x0FFFFFFF;
+ disk->write(sector, &fat);
+
+ }
+
+ return next_cluster;
+}
+
+/**
+ * @brief Searches the fat table for a free cluster starting from the first free cluster in the fsinfo, will then wrap around
+ *
+ * @return The first free cluster in the FAT table
+ */
+uint32_t Fat32Volume::find_free_cluster() {
+
+ // Get the first free cluster
+ for (uint32_t start = fsinfo.next_free_cluster; start < fat_total_clusters + 1; start++)
+ if (next_cluster(start) == 0)
+ return start;
+
+ // Check any clusters before the first free cluster
+ for (uint32_t start = 2; start < fsinfo.next_free_cluster; start++)
+ if (next_cluster(start) == 0)
+ return start;
+
+ ASSERT(false, "No free clusters found in the FAT table");
+ return 0;
+}
+
+/**
+ * @brief Allocate a cluster in the FAT table
+ *
+ * @param cluster The base cluster to start from or 0 if this is a new chain
+ * @return The next cluster in the chain
+ */
+uint32_t Fat32Volume::allocate_cluster(uint32_t cluster) {
+
+ // Allocate 1 cluster
+ return allocate_cluster(cluster, 1);
+}
+
+/**
+ * @brief Allocate a number of clusters in the FAT table, updates the fsinfo and the chain
+ *
+ * @param cluster The base cluster to start from or 0 if this is a new chain
+ * @param amount The number of clusters to allocate
+ * @return The next cluster in the chain
+ */
+uint32_t Fat32Volume::allocate_cluster(uint32_t cluster, size_t amount) {
+
+ // Make sure within bounds
+ if (cluster > fat_total_clusters || cluster + amount > fat_total_clusters)
+ return 0;
+
+ // Go through allocating the clusters
+ for (size_t i = 0; i < amount; i++) {
+ uint32_t next_cluster = find_free_cluster();
+
+ // Update the fsinfo
+ fsinfo.next_free_cluster = next_cluster + 1;
+ fsinfo.free_cluster_count -= 1;
+
+ // If there is an existing chain it needs to be updated
+ if (cluster != 0)
+ set_next_cluster(cluster, next_cluster);
+
+ cluster = next_cluster;
+ }
+
+ // Once all the updates are done flush the changes to the disk
+ buffer_t fs_info_buffer(&fsinfo, sizeof(fs_info_t));
+ disk->write(fat_info_lba, &fs_info_buffer);
+
+ // Finish the chin
+ set_next_cluster(cluster, (uint32_t) ClusterState::END_OF_CHAIN);
+ uint32_t next = next_cluster(cluster);
+ return cluster;
+}
+
+/**
+ * @brief Free a cluster in the FAT table
+ *
+ * @param cluster The base cluster to start from
+ * @param full Weather the chain's length is 1 or not
+ */
+void Fat32Volume::free_cluster(lba_t cluster) {
+
+ // Free 1 cluster
+ free_cluster(cluster, 1);
+
+}
+
+/**
+ * @brief Free a number of clusters in the FAT table
+ *
+ * @param cluster The base cluster to start from
+ * @param amount The number of clusters to free
+ */
+void Fat32Volume::free_cluster(uint32_t cluster, size_t amount) {
+
+ // Make sure within bounds
+ if (cluster < 2 || cluster > fat_total_clusters || cluster + amount > fat_total_clusters)
+ return;
+
+ // Go through freeing the clusters
+ for (size_t i = 0; i < amount; i++) {
+
+ // Find the next cluster before it is removed from the chain
+ uint32_t next_in_chain = next_cluster(cluster);
+
+ // Update the fsinfo
+ fsinfo.next_free_cluster = cluster;
+ fsinfo.free_cluster_count += 1;
+
+ // Update the chain
+ set_next_cluster(cluster, (lba_t) ClusterState::FREE);
+ cluster = next_in_chain;
+ }
+
+ // Save the fsinfo
+ buffer_t fs_info_buffer(&fsinfo, sizeof(fs_info_t));
+ disk->write(fat_info_lba, &fs_info_buffer);
+
+ // Mark the end of the chain
+ set_next_cluster(cluster, (uint32_t) ClusterState::END_OF_CHAIN);
+}
+
+
+Fat32File::Fat32File(Fat32Volume *volume, Fat32Directory *parent, dir_entry_t *info, const string &name)
+: m_volume(volume),
+ m_parent_directory(parent),
+ m_entry(info),
+ m_first_cluster((info->first_cluster_high << 16) | info->first_cluster_low)
+{
+
+ m_name = name;
+ m_size = info->size;
+ m_offset = 0;
+}
+
+Fat32File::~Fat32File() = default;
+
+/**
+ * @brief Write data to the file (at the current seek position, updated to be += amount)
+ *
+ * @param data The byte buffer to write
+ * @param amount The amount of data to write
+ */
+void Fat32File::write(const buffer_t *data, size_t amount) {
+
+ size_t buffer_space = m_volume->bpb.bytes_per_sector * m_volume->bpb.sectors_per_cluster;
+ buffer_t buffer(buffer_space);
+ buffer.clear();
+
+ uint64_t current_offset = 0;
+ uint64_t bytes_written = 0;
+ uint32_t last = m_first_cluster;
+
+ // Read the file
+ for (uint32_t cluster = last;
+ cluster != (uint32_t) ClusterState::END_OF_CHAIN; cluster = m_volume->next_cluster(cluster)) {
+ last = cluster;
+
+ // No cluster to read from (blank file)
+ if (cluster == 0)
+ break;
+
+ // Skip clusters before the offset
+ if ((current_offset + buffer_space) < m_offset) {
+ current_offset += buffer_space;
+ continue;
+ }
+
+ // Read each sector in the cluster (prevent overwriting the data)
+ lba_t lba = m_volume->data_lba + (cluster - 2) * m_volume->bpb.sectors_per_cluster;
+ for (size_t sector = 0; sector < m_volume->bpb.sectors_per_cluster; sector++)
+ m_volume->disk->read(lba + sector, &buffer, m_volume->bpb.bytes_per_sector);
+ buffer.set_offset(0);
+
+ // If the offset is in the middle of the cluster
+ size_t buffer_offset = 0;
+ if (m_offset > current_offset)
+ buffer_offset = m_offset - current_offset;
+
+ // Calculate how many bytes are being copied (read from cluster at offset?
+ // or read part of cluster?)
+ size_t cluster_remaining_bytes = buffer_space - buffer_offset;
+ size_t data_remaining_bytes = amount - bytes_written;
+ size_t bytes_to_copy = (cluster_remaining_bytes < data_remaining_bytes) ? cluster_remaining_bytes
+ : data_remaining_bytes;
+ bytes_to_copy = (bytes_to_copy > buffer_space) ? buffer_space : bytes_to_copy;
+
+ // Update the data
+ buffer.copy_from(data, bytes_to_copy, buffer_offset, bytes_written);
+ bytes_written += bytes_to_copy;
+ current_offset += bytes_to_copy;
+ buffer.set_offset(0);
+
+ // Write the data back to the disk
+ for (size_t sector = 0; sector < m_volume->bpb.sectors_per_cluster; sector++)
+ m_volume->disk->write(lba + sector, &buffer, m_volume->bpb.bytes_per_sector);
+ }
+
+ // Extend the file
+ while (bytes_written < amount) {
+ // Allocate a new cluster
+ uint32_t new_cluster = m_volume->allocate_cluster(last);
+ if (new_cluster == 0)
+ break;
+
+ if (last == 0)
+ m_first_cluster = new_cluster;
+
+ // Update the data
+ size_t bytes_to_copy = (amount - bytes_written) > buffer_space ? buffer_space : (amount - bytes_written);
+ buffer.copy_from(data, bytes_to_copy, 0, bytes_written);
+ bytes_written += bytes_to_copy;
+ current_offset += bytes_to_copy;
+ buffer.set_offset(0);
+
+ // Write the data back to the disk
+ lba_t lba = m_volume->data_lba + (new_cluster - 2) * m_volume->bpb.sectors_per_cluster;
+ for (size_t sector = 0; sector < m_volume->bpb.sectors_per_cluster; sector++)
+ m_volume->disk->write(lba + sector, &buffer, m_volume->bpb.bytes_per_sector);
+
+ // Go to the next cluster
+ last = new_cluster;
+ }
+
+ // Update file size
+ m_offset += bytes_written;
+ if (m_offset > m_size)
+ m_size = m_offset;
+
+ // Update entry info
+ m_entry->size = m_size;
+ m_entry->first_cluster_high = (m_first_cluster >> 16) & 0xFFFF;
+ m_entry->first_cluster_low = m_first_cluster & 0xFFFF;
+ // TODO: When implemented as a usermode driver save the time
+ m_parent_directory->save_entry_to_disk(m_entry);
+
+}
+
+/**
+ * @brief Read data from the file (at the current seek position, updated to be += amount)
+ *
+ * @param data The byte buffer to read into
+ * @param amount The amount of data to read
+ */
+void Fat32File::read(buffer_t *data, size_t amount) {
+ size_t buffer_space = m_volume->bpb.bytes_per_sector * m_volume->bpb.sectors_per_cluster;
+ buffer_t buffer(buffer_space);
+ buffer.clear();
+
+ uint64_t current_offset = 0;
+ uint64_t bytes_read = 0;
+
+ // Read the file
+ for (uint32_t cluster = m_first_cluster;
+ cluster != (uint32_t) ClusterState::END_OF_CHAIN; cluster = m_volume->next_cluster(cluster)) {
+
+ // Skip clusters before the offset
+ if ((current_offset + buffer_space) < m_offset) {
+ current_offset += buffer_space;
+ continue;
+ }
+
+ // Read each sector in the cluster
+ lba_t lba = m_volume->data_lba + (cluster - 2) * m_volume->bpb.sectors_per_cluster;
+ for (size_t sector = 0; sector < m_volume->bpb.sectors_per_cluster; sector++)
+ m_volume->disk->read(lba + sector, &buffer, m_volume->bpb.bytes_per_sector);
+ buffer.set_offset(0);
+
+ // If the offset is in the middle of the cluster
+ size_t buffer_offset = 0;
+ if (m_offset > current_offset)
+ buffer_offset = m_offset - current_offset;
+
+ // Calculate how many bytes are being copied (read from cluster at offset? or read part of cluster?)
+ size_t cluster_remaining_bytes = buffer_space - buffer_offset;
+ size_t data_remaining_bytes = amount - bytes_read;
+ size_t bytes_to_copy = (cluster_remaining_bytes < data_remaining_bytes) ? cluster_remaining_bytes
+ : data_remaining_bytes;
+ bytes_to_copy = (bytes_to_copy > buffer_space) ? buffer_space : bytes_to_copy;
+
+ // Read the data
+ buffer.copy_from(data, bytes_to_copy, buffer_offset, bytes_read);
+ bytes_read += bytes_to_copy;
+ current_offset += buffer_space;
+
+ // Dont read more than needed
+ if (bytes_read >= amount)
+ break;
+ }
+
+ m_offset += bytes_read;
+}
+
+/**
+ * @brief Flush the file to the disk
+ */
+void Fat32File::flush() {
+ File::flush();
+}
+
+Fat32Directory::Fat32Directory(Fat32Volume *volume, uint32_t cluster, const string &name)
+: m_volume(volume),
+ m_first_cluster(cluster)
+{
+ m_name = name;
+}
+
+Fat32Directory::~Fat32Directory() = default;
+
+/**
+ * @brief Create a new entry in the directory
+ *
+ * @param name The name of the file or directory to create
+ * @param is_directory True if the entry is a directory, false if it is a file
+ * @return The cluster of the new entry
+ */
+dir_entry_t *Fat32Directory::create_entry(const string &name, bool is_directory) {
+
+ // Allocate a cluster for the new entry
+ uint32_t cluster = m_volume->allocate_cluster(0);
+ if (cluster == 0)
+ return nullptr;
+
+ // Store the name
+ Vector lfn_entries = to_long_filenames(name);
+ char short_name[8];
+ char short_extension[3];
+ for (int i = 0; i < 8; i++)
+ short_name[i] = (i < name.length()) ? name[i] : ' ';
+ for (int i = 0; i < 3; i++)
+ short_extension[i] = (8 + i < name.length()) ? name[8 + i] : ' ';
+
+ // Create the directory entry
+ dir_entry_t entry = {};
+ memcpy(entry.name, short_name, sizeof(short_name));
+ memcpy(entry.extension, short_extension, sizeof(short_extension));
+ entry.attributes = is_directory ? (uint8_t) DirectoryEntryAttributes::DIRECTORY
+ : (uint8_t) DirectoryEntryAttributes::ARCHIVE;
+ entry.first_cluster_high = (cluster >> 16) & 0xFFFF;
+ entry.first_cluster_low = cluster & 0xFFFF;
+
+ // Find free space for the new entry and the name
+ size_t entries_needed = 1 + lfn_entries.size();
+ int entry_index = find_free_entries(entries_needed);
+ if (entry_index == -1)
+ entry_index = expand_directory(entries_needed);
+
+ // Store the entries in the cache
+ for (size_t i = 0; i < entries_needed; i++)
+ m_entries[entry_index + i] = i == 0 ? entry : *(dir_entry_t *) &lfn_entries[i - 1];
+
+ // Write the long file name entries
+ for (size_t index = entry_index + lfn_entries.size() - 1; index >= entry_index; index--)
+ update_entry_on_disk(index);
+
+ // Creating the file is done
+ if (!is_directory)
+ return &m_entries[entry_index];
+
+ // Create the "." in the directory
+ dir_entry_t current_dir_entry = {};
+ memcpy(current_dir_entry.name, ".", 1);
+ current_dir_entry.attributes = 0x10;
+ current_dir_entry.first_cluster_high = (cluster >> 16) & 0xFFFF;
+ current_dir_entry.first_cluster_low = cluster & 0xFFFF;
+
+ // Create the ".." in the directory
+ dir_entry_t parent_dir_entry = {};
+ memcpy(parent_dir_entry.name, "..", 2);
+ parent_dir_entry.attributes = 0x10;
+ parent_dir_entry.first_cluster_high = (m_first_cluster >> 16) & 0xFFFF;
+ parent_dir_entry.first_cluster_low = m_first_cluster & 0xFFFF;
+
+ // Write the entries to the disk
+ uint32_t bytes_per_sector = m_volume->bpb.bytes_per_sector;
+ lba_t child_lba = m_volume->data_lba + (cluster - 2) * bytes_per_sector;
+ buffer_t buffer(bytes_per_sector);
+ buffer.clear();
+ buffer.copy_from(¤t_dir_entry, sizeof(dir_entry_t));
+ buffer.copy_from(&parent_dir_entry, sizeof(dir_entry_t));
+ m_volume->disk->write(child_lba, &buffer);
+
+ // Directory created
+ return &m_entries[entry_index];
+}
+
+/**
+ * @brief Remove an entry from the directory
+ *
+ * @param cluster The cluster of the entry to remove
+ * @param name The name of the entry to remove
+ */
+void Fat32Directory::remove_entry(uint32_t cluster, const string &name) {
+
+ // Find the entry in the directory
+ int entry = entry_index(cluster);
+ if (entry == -1)
+ return;
+
+ // Find any long file name entries that belong to this entry
+ size_t delete_entry_index = entry;
+ while (delete_entry_index > 0 &&
+ m_entries[delete_entry_index - 1].attributes == (uint8_t) DirectoryEntryAttributes::LONG_NAME)
+ delete_entry_index--;
+
+ // Mark the entries as free
+ for (size_t i = delete_entry_index; i < entry; i++)
+ m_entries[i].name[0] = (uint8_t) DirectoryEntryType::FREE;
+
+ // Update the entries on the disk
+ for (size_t i = delete_entry_index; i <= entry; i++)
+ update_entry_on_disk(i);
+
+ // Count the number of clusters in the chain
+ size_t cluster_count = 0;
+ for (uint32_t next_cluster = cluster;
+ next_cluster < (lba_t) ClusterState::BAD; next_cluster = m_volume->next_cluster(next_cluster))
+ cluster_count++;
+
+ // Free all the clusters in the chain
+ m_volume->free_cluster(cluster, cluster_count);
+}
+
+/**
+ * @brief Read all of the directory entries for each cluster in this directory
+ */
+void Fat32Directory::read_all_entries() {
+ m_entries.clear();
+
+ size_t buffer_space = m_volume->bpb.bytes_per_sector * m_volume->bpb.sectors_per_cluster;
+ buffer_t buffer(buffer_space);
+ buffer.clear();
+
+ // Read the directory
+ for (uint32_t cluster = m_first_cluster;
+ cluster != (uint32_t) ClusterState::END_OF_CHAIN; cluster = m_volume->next_cluster(cluster)) {
+
+ // Cache info to prevent re-traversing the chain
+ m_last_cluster = cluster;
+ m_current_cluster_length++;
+
+ // Read each sector in the cluster
+ lba_t lba = m_volume->data_lba + (cluster - 2) * m_volume->bpb.sectors_per_cluster;
+ for (size_t sector = 0; sector < m_volume->bpb.sectors_per_cluster; sector++)
+ m_volume->disk->read(lba + sector, &buffer, m_volume->bpb.bytes_per_sector);
+
+ // Parse the directory entries (each entry is 32 bytes)
+ for (size_t entry_offset = 0; entry_offset < buffer_space; entry_offset += 32) {
+
+ // Store the entry
+ auto entry = (dir_entry_t *) &(buffer.raw()[entry_offset]);
+ m_entries.push_back(*entry);
+
+ // Check if the entry is the end of the directory
+ if (entry->name[0] == (uint8_t) DirectoryEntryType::LAST)
+ return;
+ }
+
+ }
+}
+
+
+/**
+ * @brief Writes an updated directory entry to the disk
+ *
+ * @param entry The entry to write
+ */
+void Fat32Directory::save_entry_to_disk(DirectoryEntry *entry) {
+
+ int index = 0;
+ for (auto &m_entry: m_entries) {
+ if (&m_entry == entry)
+ break;
+ index++;
+ }
+
+ update_entry_on_disk(index);
+}
+
+void Fat32Directory::update_entry_on_disk(int index) {
+
+ // Get the entry
+ auto entry = m_entries[index];
+
+ // Determine sector offset and in-sector byte offset
+ uint32_t bytes_per_sector = m_volume->bpb.bytes_per_sector;
+ uint32_t entry_offset = index * sizeof(dir_entry_t);
+ uint32_t sector_offset = entry_offset / bytes_per_sector;
+ uint32_t in_sector_offset = entry_offset % bytes_per_sector;
+
+ // Find which cluster has the entry
+ uint32_t cluster = m_first_cluster;
+ for (uint32_t offset_remaining = entry_offset;
+ offset_remaining >= bytes_per_sector; offset_remaining -= bytes_per_sector)
+ cluster = m_volume->next_cluster(cluster);
+
+ // Read the full sector into a buffer
+ lba_t base_lba = m_volume->data_lba + (cluster - 2) * m_volume->bpb.sectors_per_cluster;
+ buffer_t sector_buffer(bytes_per_sector, false);
+ m_volume->disk->read(base_lba + sector_offset, §or_buffer);
+
+ // Update the entry in the buffer
+ sector_buffer.copy_from(&entry, sizeof(dir_entry_t), in_sector_offset);
+ m_volume->disk->write(base_lba + sector_offset, §or_buffer);
+}
+
+/**
+ * @brief Find cluster's directory entry index in the store entries
+ *
+ * @param cluster The cluster
+ * @return The index or -1 if not found
+ */
+int Fat32Directory::entry_index(lba_t cluster) {
+
+ int entry_index = 0;
+ for (; entry_index < m_entries.size(); entry_index++) {
+ auto &entry = m_entries[entry_index];
+
+ // End of directory means no more entries
+ if (entry.name[0] == (uint8_t) DirectoryEntryType::LAST)
+ return -1;
+
+ // Skip free entries
+ if (entry.name[0] == (uint8_t) DirectoryEntryType::FREE)
+ continue;
+
+ // Check if the entry is the one
+ uint32_t start_cluster = (entry.first_cluster_high << 16) | entry.first_cluster_low;
+ if (start_cluster == cluster)
+ break;
+ }
+
+ // Make sure the entry is valid
+ if (entry_index >= m_entries.size())
+ return -1;
+
+ return entry_index;
+
+}
+
+/**
+ * @brief Find a series of free entries in a row
+ *
+ * @param amount The amount of adjacent entries to find
+ *
+ * @return The index of the first free entry or -1 if cant find that many free entries
+ */
+int Fat32Directory::find_free_entries(size_t amount) {
+
+ for (int entry_index = 0; entry_index < m_entries.size(); entry_index++) {
+ // Check if there are enough free entries in a row
+ bool found = true;
+ for (size_t j = 0; j < amount; j++)
+ if (m_entries[entry_index + j].name[0] != (char) DirectoryEntryType::FREE)
+ found = false;
+
+ if (found)
+ return entry_index;
+ }
+
+ return -1;
+}
+
+
+/**
+ * @brief Expand the directory to fit 'amount - free' more entries.
+ *
+ * @note Caller must write data to the entries as only the updated LAST entry is
+ * saved to disk. Theoretically there wont be an issue if caller doesn't as the
+ * old LAST will still be in the same space.
+ *
+ * @param amount How many free entries are needed
+ * @return The index of the first free entry in the chain
+ */
+int Fat32Directory::expand_directory(size_t amount) {
+
+ // Remove the old end of directory marker
+ int free_start = m_entries.size() - 1;
+ ASSERT(m_entries[free_start].name[0] == (uint8_t) DirectoryEntryType::LAST, "Last entry is not marked");
+ m_entries[free_start].name[0] = (uint8_t) DirectoryEntryType::FREE;
+
+ // Count how many free entries there is before the end
+ for (int i = free_start; i >= 0; --i) {
+ if (m_entries[i].name[0] == (char) DirectoryEntryType::FREE)
+ free_start = i;
+ else
+ break;
+ }
+
+ // Calculate how many entries are need to be created (ie was there enough free entries already)
+ uint32_t found = m_entries.size() - free_start;
+ uint32_t needed_entries = amount + 1;
+ uint32_t additional_entries = 0;
+ if (needed_entries > found)
+ additional_entries = needed_entries - found;
+
+ // Find the length of the current cluster chain
+ uint32_t total_entries = m_entries.size() + additional_entries;
+ uint32_t total_clusters = (total_entries * sizeof(dir_entry_t)) /
+ (m_volume->bpb.bytes_per_sector * m_volume->bpb.sectors_per_cluster);
+
+ // Expand the cluster chain if needed
+ if (total_clusters > m_current_cluster_length) {
+ m_volume->allocate_cluster(m_last_cluster, total_clusters - m_current_cluster_length);
+ m_current_cluster_length = total_clusters;
+ }
+
+ // Expand the directory to fit the remaining entries
+ for (int i = 0; i < additional_entries; ++i) {
+ dir_entry_t free = {};
+ free.name[0] = (uint8_t) DirectoryEntryType::FREE;
+ m_entries.push_back(free);
+ }
+
+ // Write the updated end of entries
+ m_entries[m_entries.size() - 1].name[0] = (uint8_t) DirectoryEntryType::LAST;
+ update_entry_on_disk(m_entries.size() - 1);
+
+ return free_start;
+}
+
+/**
+ * @brief Converts a string into a series of long file name entries (in reverse
+ * order, correct directory entry order)
+ *
+ * @param name The name
+ * @return A vector of longfile names
+ */
+Vector