<repo_name>doytsujin/CyanOS<file_sep>/kernel/Tasking/WaitQueue.h
#pragma once
#include "Thread.h"
#include "Utils/IntrusiveList.h"

class WaitQueue
{
  public:
	WaitQueue();
	void enqueue(Thread& thread);
	void wake_up();
	void wake_up(size_t num);
	void wake_up_all();

	WaitQueue(WaitQueue&&) = delete;
	WaitQueue(const WaitQueue&) = delete;
	WaitQueue& operator=(WaitQueue&&) = delete;
	WaitQueue& operator=(const WaitQueue&) = delete;
	~WaitQueue();

  private:
	Spinlock m_lock;
	IntrusiveList<Thread> m_threads;
};
<file_sep>/kernel/Boot/Boot.h
#pragma once

#include "Arch/x86/Asm.h"
#include "Kernel_init.h"
#include "Kernel_map.h"
#include "Multiboot2.h"
#include "Utils/Assert.h"
#include "Utils/Types.h"
#include "VirtualMemory/Memory.h"

typedef struct __attribute__((__packed__)) {
	multiboot_header header __attribute__((aligned(MULTIBOOT_HEADER_ALIGN)));
	multiboot_header_tag_address address __attribute__((aligned(MULTIBOOT_HEADER_ALIGN)));
	multiboot_header_tag_entry_address entry __attribute__((aligned(MULTIBOOT_HEADER_ALIGN)));
	multiboot_header_tag_module_align mod_align __attribute__((aligned(MULTIBOOT_HEADER_ALIGN)));
	multiboot_header_tag end __attribute__((aligned(MULTIBOOT_HEADER_ALIGN)));
} Mutiboot2_Header;
#define MULTIBOOT2_HEADER_CHECKSUM ((uint32_t)(-sizeof(Mutiboot2_Header) - MULTIBOOT2_HEADER_MAGIC))

#define STACK_SIZE 0x4000

extern uint32_t kernel_boot_stage1;
extern "C" void kernel_boot_stage2(uint32_t magic, multiboot_tag_start* boot_info);
BootloaderInfo parse_mbi(uintptr_t multiboot_info);
uintptr_t align_to(uintptr_t size, unsigned alignment);<file_sep>/kernel/Tasking/Semaphore.h
#pragma once

#include "Utils/Types.h"
#include "WaitQueue.h"

class Semaphore
{
  private:
	Spinlock m_spinlock;
	unsigned m_max_count;
	unsigned m_count;
	WaitQueue m_queue;

  public:
	explicit Semaphore(size_t t_max_count, size_t t_initial_value = 0);
	~Semaphore();
	void acquire();
	void release();
};
<file_sep>/kernel/Filesystem/Pipes/PipeFS.h
#pragma once

#include "Filesystem/FSNode.h"
#include "Pipe.h"
#include "Tasking/WaitQueue.h"
#include "Utils/CircularBuffer.h"
#include "Utils/List.h"
#include "Utils/String.h"
#include "Utils/StringView.h"
#include "Utils/Types.h"
#include "Utils/UniquePointer.h"

class PipeFS : public FSNode
{

  private:
	List<Pipe> m_children;
	Spinlock m_lock;

	explicit PipeFS(const StringView& name);

  public:
	static UniquePointer<FSNode> alloc(const StringView& name);

	~PipeFS();
	Result<FSNode&> create(const StringView& name, OpenMode mode, OpenFlags flags) override;
	Result<FSNode&> dir_lookup(const StringView& file_name) override;
};<file_sep>/kernel/Filesystem/Ustar/INode.cpp
#include "INode.h"
#include "Lib/Stdlib.h"
#include "Tasking/ScopedLock.h"
#include "Utils/ErrorCodes.h"
#include "Utils/Stl.h"

INode::INode(const StringView& name, NodeType type, size_t size, char* data) :
    FSNode(name, 0, 0, type, size),
    m_data{data},
    m_lock{},
    m_children{}
{
	m_lock.init();
}

INode::~INode()
{
}

Result<void> INode::open(OpenMode mode, OpenFlags flags)
{
	UNUSED(mode);
	UNUSED(flags);

	ScopedLock local_lock(m_lock);
	return ResultError(ERROR_SUCCESS);
}

Result<void> INode::close()
{
	ScopedLock local_lock(m_lock);
	return ResultError(ERROR_SUCCESS);
}

Result<void> INode::read(void* buff, size_t offset, size_t size)
{
	ScopedLock local_lock(m_lock);
	ASSERT((offset + size) <= m_size);
	memcpy(buff, m_data + offset, size);
	return ResultError(ERROR_SUCCESS);
}

Result<bool> INode::can_read()
{
	return true;
}

Result<FSNode&> INode::dir_lookup(const StringView& file_name)
{
	ScopedLock local_lock(m_lock);
	for (auto& i : m_children) {
		if (i.m_name == file_name) {
			return i;
		}
	}
	return ResultError(ERROR_FILE_DOES_NOT_EXIST);
}
<file_sep>/kernel/Arch/x86/Spinlock.h
#pragma once

#include "Asm.h"
#include "Utils/Types.h"

class StaticSpinlock
{
  private:
	uint32_t m_value;
	uint32_t m_eflags;

  public:
	void init();
	void acquire();
	void release();
	StaticSpinlock() = default;
	~StaticSpinlock() = default;
};
<file_sep>/kernel/Tasking/Process.cpp
#include "Process.h"
#include "Arch/x86/Context.h"
#include "Filesystem/VirtualFilesystem.h"
#include "Loader/PE.h"
#include "ScopedLock.h"
#include "Thread.h"
#include "Utils/Assert.h"
#include "VirtualMemory/Memory.h"

List<Process>* Process::processes;
Bitmap* Process::pid_bitmap;
StaticSpinlock Process::global_lock;

void Process::setup()
{
	pid_bitmap = new Bitmap(MAX_BITMAP_SIZE);
	processes = new List<Process>;
	global_lock.init();
}

Process& Process::create_new_process(const StringView& name, const StringView& path)
{
	ScopedLock local_lock(global_lock);
	auto& pcb = processes->emplace_back(name, path);
	Thread::create_thread(pcb, initiate_process, uintptr_t(&pcb));
	return pcb;
}

Process::Process(const StringView& name, const StringView& path) :
    m_lock{},
    m_pid{reserve_pid()},
    m_name{name},
    m_path{path},
    m_page_directory{Memory::create_new_virtual_space()},
    m_state{ProcessState::ACTIVE},
    m_parent{nullptr},
    m_file_descriptors{}
{
	m_lock.init();
}

Process::~Process()
{
}

Result<uintptr_t> Process::load_executable(const StringView& path)
{
	ScopedLock local_lock(m_lock);
	auto fd = VFS::open(path, OpenMode::Read, OpenFlags::OpenExisting);
	if (fd.is_error()) {
		warn() << "error opening the executable file, error: " << fd.error();
		return ResultError(fd.error());
	}
	auto file_info = fd.value()->fstat();
	// FIXME: implement smart pointers and use it here.
	char* buff = static_cast<char*>(Memory::alloc(file_info.value().size, MEMORY_TYPE::KERNEL | MEMORY_TYPE::WRITABLE));
	memset(buff, 0, file_info.value().size);
	auto result = fd.value()->read(buff, file_info.value().size);
	if (result.is_error()) {
		return ResultError(result.error());
	}

	auto execable_entrypoint = PELoader::load(buff, file_info.value().size);
	if (execable_entrypoint.is_error()) {
		return ResultError(execable_entrypoint.error());
	}
	Memory::free(buff, file_info.value().size, 0);
	return execable_entrypoint.value();
}

unsigned Process::reserve_pid()
{
	unsigned id = pid_bitmap->find_first_unused();
	pid_bitmap->set_used(id);
	return id;
}

void Process::initiate_process(uintptr_t __pcb)
{
	Process* pcb = reinterpret_cast<Process*>(__pcb);
	auto&& executable_entrypoint = pcb->load_executable(pcb->m_path);
	if (executable_entrypoint.is_error()) {
		warn() << "couldn't load the process, error: " << executable_entrypoint.error() << "\n";
		return; // Remove thread
	}
	// return ResultError(execable_entrypoint.error());
	void* thread_user_stack = Memory::alloc(STACK_SIZE, MEMORY_TYPE::WRITABLE);
	Context::enter_usermode(executable_entrypoint.value(), uintptr_t(thread_user_stack) + STACK_SIZE);
	ASSERT_NOT_REACHABLE();
}<file_sep>/kernel/Utils/CircularList.h
#pragma once

#include "Stl.h"
#include "Types.h"
#ifdef __UNIT_TESTS
	#include <assert.h>
	#define ASSERT(x) assert(x)
#else
	#include "Assert.h"
#endif

template <class T> class CircularQueue
{
  private:
	struct Node {
		T data;
		Node *next, *prev;
	};
	Node* m_head;
	size_t m_count;
	void unlink_node(Node* node);
	void link_node(Node* new_node, Node* pnode);

  public:
	class Iterator
	{
	  private:
		Node* m_current;
		Node* m_head;

	  public:
		Iterator(Node* t_list);
		Node* node();
		void move_cursor(int index);
		Iterator& operator++(int);
		Iterator& operator++();
		bool operator!=(const CircularQueue<T>::Iterator& other);
		bool operator==(const CircularQueue<T>::Iterator& other);
		void operator=(const CircularQueue<T>::Iterator& other);
		T* operator->();
		T& operator*();
	};
	CircularQueue();
	~CircularQueue();
	Iterator begin();
	Iterator end();
	template <typename... U> T& emplace_back(U&&... u);
	template <typename... U> T& emplace_front(U&&... u);
	T& push_back(const T& new_data);
	T& push_front(const T& new_data);
	T& push_back(T&& new_data);
	T& push_front(T&& new_data);
	void pop_back();
	void pop_front();
	void remove(Iterator&);
	void remove(int index);
	void increment_head();
	void set_head(Iterator&);
	void set_head(int index);
	void move_to_other_list(CircularQueue<T>* list, Iterator& itr);
	void move_head_to_other_list(CircularQueue<T>* list);
	bool is_empty();
	size_t size();
	T& head();
	T& operator[](int index);
};

template <class T> CircularQueue<T>::Iterator::Iterator(Node* t_node) : m_current(t_node), m_head(t_node)
{
}

// move the current node pointer number of nodes forward or backward relative to the current head.
template <class T> void CircularQueue<T>::Iterator::move_cursor(int index)
{
	Node* p = m_head;
	if (index > 0) {
		while (index--) {
			p = p->next;
		}
	} else {
		while (index++) {
			p = p->prev;
		}
	}
	m_current = p;
}

// Increment the current node pointer.
template <class T> typename CircularQueue<T>::Iterator& CircularQueue<T>::Iterator::operator++(int arg)
{
	const auto next = m_current->next;
	if (next == m_head) {
		m_current = nullptr; // iterated through the whole list.
	} else {
		m_current = next;
	}
	return *this;
}

// Increment the current node pointer.
template <class T> typename CircularQueue<T>::Iterator& CircularQueue<T>::Iterator::operator++()
{
	const auto next = m_current->next;
	if (next == m_head) {
		m_current = nullptr; // iterated through the whole list.
	} else {
		m_current = next;
	}
	return *this;
}

template <class T> bool CircularQueue<T>::Iterator::operator!=(const CircularQueue<T>::Iterator& other)
{
	return m_current != other.m_current;
}

template <class T> bool CircularQueue<T>::Iterator::operator==(const CircularQueue<T>::Iterator& other)
{
	return m_current == other.m_current;
}

template <class T> void CircularQueue<T>::Iterator::operator=(const CircularQueue<T>::Iterator& other)
{
	m_current = other->m_current;
	m_head = other->m_head;
}

template <class T> T& CircularQueue<T>::Iterator::operator*()
{
	return m_current->data;
}

template <class T> T* CircularQueue<T>::Iterator::operator->()
{
	return &m_current->data;
}

// Get node pointer.
template <class T> typename CircularQueue<T>::Node* CircularQueue<T>::Iterator::node()
{
	return m_current;
}

template <class T> CircularQueue<T>::CircularQueue() : m_head(nullptr), m_count(0)
{
}

template <class T> CircularQueue<T>::~CircularQueue()
{
	if (!m_head)
		return;

	Node* node_iterator = m_head;
	do {
		Node* next = node_iterator->next;
		delete node_iterator;
		node_iterator = next;
	} while (node_iterator != m_head);
}

// Move node to other list.
template <class T> void CircularQueue<T>::move_to_other_list(CircularQueue<T>* list, Iterator& itr)
{
	ASSERT(list);
	unlink_node(itr.node());
	list->link_node(itr.node(), list->m_head);
}

// Move head node to other list.
template <class T> void CircularQueue<T>::move_head_to_other_list(CircularQueue<T>* list)
{
	ASSERT(list);
	Node* node = m_head;
	unlink_node(node);
	list->link_node(node, list->m_head);
}

// unlink node from the list.
template <class T> void CircularQueue<T>::unlink_node(Node* node)
{
	ASSERT(m_head);
	ASSERT(node);
	if (node == node->next) { // remove the last node
		m_head = nullptr;
	} else {
		if (node == m_head) {
			m_head = node->next;
		}
		node->prev->next = node->next;
		node->next->prev = node->prev;
	}
	m_count--;
}

// link a new node before `pnode`.
template <class T> void CircularQueue<T>::link_node(Node* new_node, Node* pnode)
{
	ASSERT(new_node);
	if (pnode) {
		new_node->next = pnode;
		new_node->prev = pnode->prev;
		pnode->prev->next = new_node;
		pnode->prev = new_node;
	} else {
		new_node->next = new_node->prev = new_node;
	}
	if (!m_head) {
		m_head = new_node;
	}
	m_count++;
}

// Get iterator object for the head node.
template <class T> typename CircularQueue<T>::Iterator CircularQueue<T>::begin()
{
	return Iterator(m_head);
}

// Get iterator object for the last node.
template <class T> typename CircularQueue<T>::Iterator CircularQueue<T>::end()
{
	return Iterator(nullptr);
}

template <class T> template <typename... U> T& CircularQueue<T>::emplace_back(U&&... u)
{
	Node* new_node = new Node{T{forward<U>(u)...}, nullptr, nullptr};
	link_node(new_node, m_head);
	return new_node->data;
}

template <class T> template <typename... U> T& CircularQueue<T>::emplace_front(U&&... u)
{
	Node* new_node = new Node{T{forward<U>(u)...}, nullptr, nullptr};
	link_node(new_node, m_head);
	m_head = m_head->prev;
	return new_node->data;
}

// Push data to the back of the list.
template <class T> T& CircularQueue<T>::push_back(const T& new_data)
{
	Node* new_node = new Node{new_data, nullptr, nullptr};
	link_node(new_node, m_head);
	return new_node->data;
}

template <class T> T& CircularQueue<T>::push_front(const T& new_data)
{
	T& new_node_data = push_back(new_data);
	m_head = m_head->prev;
	return new_node_data;
}

// Push data to the back of the list.
template <class T> T& CircularQueue<T>::push_back(T&& new_data)
{
	Node* new_node = new Node{move(new_data), nullptr, nullptr};
	link_node(new_node, m_head);
	return new_node->data;
}

template <class T> T& CircularQueue<T>::push_front(T&& new_data)
{
	T& new_node_data = push_back(move(new_data));
	m_head = m_head->prev;
	return new_node_data;
}

// The second node will be the head.
template <class T> void CircularQueue<T>::increment_head()
{
	ASSERT(m_head);
	m_head = m_head->next;
}

// Select the head node using Iterator.
template <class T> void CircularQueue<T>::set_head(Iterator& itr)
{
	ASSERT(m_head);
	m_head = itr.node();
}

// Select the head node using an index.
template <class T> void CircularQueue<T>::set_head(int index)
{
	ASSERT(m_head);
	Iterator itr(m_head);
	itr.move_cursor(index);
	m_head = itr.node();
}

// Remove the last node.
template <class T> void CircularQueue<T>::pop_back()
{
	ASSERT(m_head);
	Node* node = m_head->prev;
	unlink_node(node);
	delete node;
}

// Remove the first node.
template <class T> void CircularQueue<T>::pop_front()
{
	ASSERT(m_head);
	Node* node = m_head;
	unlink_node(node);
	delete node;
}

// Remove a node whose selected by Iterator.
template <class T> void CircularQueue<T>::remove(Iterator& itr)
{

	ASSERT(m_head);
	Node* node = itr.node();
	unlink_node(node);
	delete node;
}

// Remove a node whose selected by its index.
template <class T> void CircularQueue<T>::remove(int index)
{
	ASSERT(m_head);
	Iterator itr(m_head);
	itr.move_cursor(index);
	remove(itr);
}

// Get data of the head node.
template <class T> T& CircularQueue<T>::head()
{
	ASSERT(m_head);
	return m_head->data;
}

template <class T> T& CircularQueue<T>::operator[](int index)
{
	ASSERT(m_head);
	Iterator itr(m_head);
	itr.move_cursor(index);
	return *itr;
}

template <class T> bool CircularQueue<T>::is_empty()
{
	if (m_count)
		return false;
	else
		return true;
}

template <class T> size_t CircularQueue<T>::size()
{
	return m_count;
}<file_sep>/kernel/VirtualMemory/Virtual.h
#pragma once

#include "Arch/x86/Paging.h"
#include "Arch/x86/Panic.h"
#include "Kernel_map.h"
#include "Memory.h"
#include "Utils/Assert.h"
#include "Utils/Types.h"

class VirtualMemory
{
  private:
  public:
	static uintptr_t find_pages(uint32_t start_address, uint32_t end_address, uint32_t pages_num);
	static uintptr_t create_page_table();
	static bool check_free_pages(uint32_t start_address, uint32_t pages_num);
	static void map_pages(uintptr_t virtual_address, uintptr_t physical_address, uint32_t pages, uint32_t flags);
};
<file_sep>/kernel/Tasking/Loader/Winnt.h
#pragma once

#include "Utils/Types.h"

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
#define IMAGE_NT_SIGNATURE               0x00004550
#define IMAGE_DOS_SIGNATURE              0x5A4D
#define IMAGE_NT_OPTIONAL_HDR32_MAGIC    0x10b
#define IMAGE_SIZEOF_SHORT_NAME          8

#pragma pack(1)
typedef struct _IMAGE_DOS_HEADER {
	uint16_t e_magic;
	uint16_t e_cblp;
	uint16_t e_cp;
	uint16_t e_crlc;
	uint16_t e_cparhdr;
	uint16_t e_minalloc;
	uint16_t e_maxalloc;
	uint16_t e_ss;
	uint16_t e_sp;
	uint16_t e_csum;
	uint16_t e_ip;
	uint16_t e_cs;
	uint16_t e_lfarlc;
	uint16_t e_ovno;
	uint16_t e_res[4];
	uint16_t e_oemid;
	uint16_t e_oeminfo;
	uint16_t e_res2[10];
	uint32_t e_lfanew;
} IMAGE_DOS_HEADER;

typedef struct _IMAGE_FILE_HEADER {
	uint16_t Machine;
	uint16_t NumberOfSections;
	uint32_t TimeDateStamp;
	uint32_t PointerToSymbolTable;
	uint32_t NumberOfSymbols;
	uint16_t SizeOfOptionalHeader;
	uint16_t Characteristics;
} IMAGE_FILE_HEADER;

typedef struct _IMAGE_DATA_DIRECTORY {
	uint32_t VirtualAddress;
	uint32_t Size;
} IMAGE_DATA_DIRECTORY;

typedef struct _IMAGE_OPTIONAL_HEADER {
	uint16_t Magic;
	uint8_t MajorLinkerVersion;
	uint8_t MinorLinkerVersion;
	uint32_t SizeOfCode;
	uint32_t SizeOfInitializedData;
	uint32_t SizeOfUninitializedData;
	uint32_t AddressOfEntryPoint;
	uint32_t BaseOfCode;
	uint32_t BaseOfData;
	uint32_t ImageBase;
	uint32_t SectionAlignment;
	uint32_t FileAlignment;
	uint16_t MajorOperatingSystemVersion;
	uint16_t MinorOperatingSystemVersion;
	uint16_t MajorImageVersion;
	uint16_t MinorImageVersion;
	uint16_t MajorSubsystemVersion;
	uint16_t MinorSubsystemVersion;
	uint32_t Win32VersionValue;
	uint32_t SizeOfImage;
	uint32_t SizeOfHeaders;
	uint32_t CheckSum;
	uint16_t Subsystem;
	uint16_t DllCharacteristics;
	uint32_t SizeOfStackReserve;
	uint32_t SizeOfStackCommit;
	uint32_t SizeOfHeapReserve;
	uint32_t SizeOfHeapCommit;
	uint32_t LoaderFlags;
	uint32_t NumberOfRvaAndSizes;
	IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32;

typedef struct _IMAGE_NT_HEADERS {
	uint32_t Signature;
	IMAGE_FILE_HEADER FileHeader;
	IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32;

typedef struct _IMAGE_SECTION_HEADER {
	uint8_t Name[IMAGE_SIZEOF_SHORT_NAME];
	union {
		uint32_t PhysicalAddress;
		uint32_t VirtualSize;
	} Misc;
	uint32_t VirtualAddress;
	uint32_t SizeOfRawData;
	uint32_t PointerToRawData;
	uint32_t PointerToRelocations;
	uint32_t PointerToLinenumbers;
	uint16_t NumberOfRelocations;
	uint16_t NumberOfLinenumbers;
	uint32_t Characteristics;
} IMAGE_SECTION_HEADER;
#pragma pack()<file_sep>/kernel/Tasking/Thread.h
#pragma once
#include "Arch/x86/Spinlock.h"
#include "Process.h"
#include "Utils/Bitmap.h"
#include "Utils/IntrusiveList.h"
#include "Utils/IterationDecision.h"
#include "Utils/Result.h"
#include "Utils/Types.h"

enum class ThreadState {
	RUNNABLE,
	BLOCKED_SLEEP,
	BLOCKED_QUEUE,
	BLOCKED_IO,
	SUSPENDED,
};
const size_t STACK_SIZE = 0x1000;

class WaitQueue;

class Thread : public IntrusiveListNode<Thread>
{
  private:
	typedef void (*thread_function)(uintptr_t argument);
	static void idle(_UNUSED_PARAM(uintptr_t));
	static Bitmap* m_tid_bitmap;
	static IntrusiveList<Thread>* ready_threads;
	static IntrusiveList<Thread>* sleeping_threads;
	static StaticSpinlock global_lock;

	Spinlock m_lock;
	const unsigned m_tid;
	unsigned m_sleep_ticks;
	uintptr_t m_kernel_stack_start;
	uintptr_t m_kernel_stack_end;
	uintptr_t m_kernel_stack_pointer;
	uintptr_t m_user_stack_start;
	Process& m_parent;
	ThreadState m_state;
	unsigned reserve_tid();
	Thread(Process& process, thread_function address, uintptr_t argument);

  public:
	static Thread* current;
	static Thread& create_thread(Process& parent_process, thread_function address, uintptr_t argument);
	static void sleep(unsigned ms);
	static void yield();
	static void setup();

	void wake_up_from_queue();
	void wake_up_from_sleep();
	void wait_on(WaitQueue& queue);
	void terminate();
	~Thread();
	unsigned tid();
	ThreadState state();
	Process& parent_process();

	static size_t number_of_ready_threads();

	template <typename Callback> static void for_each_sleeping(Callback callback)
	{
		auto&& thread = Thread::sleeping_threads->begin();
		while (thread != Thread::sleeping_threads->end()) {
			auto iterator_copy = thread++;
			auto ret = callback(*iterator_copy);
			if (ret == IterationDecision::Break) {
				break;
			}
		}
	}

	template <typename Callback> static void for_each_ready(Callback callback)
	{
		auto&& thread = Thread::ready_threads->begin();
		while (thread != Thread::ready_threads->end()) {
			auto iterator_copy = thread++;
			auto ret = callback(*iterator_copy);
			if (ret == IterationDecision::Break) {
				break;
			}
		}
	}
	friend class Scheduler;
	friend class WaitQueue;
};
<file_sep>/kernel/Utils/IntrusiveList.h
#pragma once

#include "Utils/Types.h"
#ifdef __UNIT_TESTS
	#include <assert.h>
	#define ASSERT(x) assert(x)
#else
	#include "Assert.h"
#endif

template <typename T> class IntrusiveList;
// Inherit from this class to use it in IntrusiveList
template <typename T> class IntrusiveListNode
{
	T* next = nullptr;
	T* prev = nullptr;
	IntrusiveList<T>* owner = nullptr;
	friend class IntrusiveList<T>;
};

template <typename T> class IntrusiveList
{
  private:
	T* m_head = nullptr;
	T* m_tail = nullptr;
	size_t m_count = 0;

	void remove_node(T& node);
	void append_node(T& node);

  public:
	class Iterator
	{
	  public:
		Iterator(T* node);
		Iterator(const Iterator& other);
		~Iterator() = default;
		bool operator==(const Iterator& other);
		bool operator!=(const Iterator& other);
		Iterator& operator++();
		Iterator operator++(int);
		T& operator*();
		T* operator->();

	  private:
		T* m_node = nullptr;
	};
	IntrusiveList() = default;
	~IntrusiveList() = default;
	IntrusiveList(const IntrusiveList&) = delete;
	IntrusiveList(IntrusiveList&&) = delete;
	IntrusiveList& operator=(const IntrusiveList&) = delete;
	IntrusiveList& operator=(IntrusiveList&&) = delete;

	void push_back(T& node);
	T* pop_front();
	T* remove(T& node);
	Iterator begin() const;
	Iterator end() const;

	T* first() const
	{
		return m_head;
	}

	T* tail() const
	{
		return m_tail;
	}

	bool is_empty() const
	{
		return !m_count;
	}

	size_t size() const
	{
		return m_count;
	}
};
template <typename T> IntrusiveList<T>::Iterator::Iterator(T* node) : m_node{node}
{
}

template <typename T> IntrusiveList<T>::Iterator::Iterator(const Iterator& other) : m_node{other.m_node}
{
}

template <typename T> bool IntrusiveList<T>::Iterator::operator==(const Iterator& other)
{
	return m_node == other.m_node;
}

template <typename T> bool IntrusiveList<T>::Iterator::operator!=(const Iterator& other)
{
	return m_node != other.m_node;
}

template <typename T> typename IntrusiveList<T>::Iterator& IntrusiveList<T>::Iterator::operator++()
{
	m_node = m_node->next;
	return *this;
}

template <typename T> typename IntrusiveList<T>::Iterator IntrusiveList<T>::Iterator::operator++(int)
{
	Iterator old(*this);
	m_node = m_node->next;
	return old;
}

template <typename T> T& IntrusiveList<T>::Iterator::operator*()
{
	return *m_node;
}

template <typename T> T* IntrusiveList<T>::Iterator::operator->()
{
	return m_node;
}

template <typename T> void IntrusiveList<T>::remove_node(T& node)
{
	ASSERT(node.owner == this);
	if ((m_head == &node) && (m_tail == &node)) {
		m_head = m_tail = nullptr;
	} else if (m_head == &node) {
		m_head = node.next;
		node.next->prev = nullptr;
	} else if (m_tail == &node) {
		m_tail = node.prev;
		node.prev->next = nullptr;
	} else {
		node.prev->next = node.next;
		node.next->prev = node.prev;
	}
	node.owner = nullptr;
	m_count--;
}

template <typename T> void IntrusiveList<T>::append_node(T& node)
{
	if (node.owner == nullptr)
		node.owner = this;

	if (!m_head) {
		node.prev = nullptr;
		node.next = nullptr;
		m_head = m_tail = &node;
	} else {
		node.prev = m_tail;
		node.next = nullptr;
		m_tail->next = &node;
		m_tail = &node;
	}
	m_count++;
}

template <typename T> void IntrusiveList<T>::push_back(T& node)
{
	append_node(node);
}

template <typename T> T* IntrusiveList<T>::pop_front()
{
	if (!m_head) {
		return nullptr;
	}
	T* node = m_head;
	remove_node(*node);
	return node;
}

template <typename T> T* IntrusiveList<T>::remove(T& node)
{
	remove_node(node);
	return &node;
}

template <typename T> typename IntrusiveList<T>::Iterator IntrusiveList<T>::begin() const
{
	return Iterator(m_head);
}

template <typename T> typename IntrusiveList<T>::Iterator IntrusiveList<T>::end() const
{
	return Iterator(nullptr);
}<file_sep>/kernel/Utils/Assert.h
#pragma once
#include "Arch/x86/Panic.h"
#ifdef NDEBUG
    /*
     * If not debugging, assert does nothing.
     */
	#define ASSERT(x)              ((void)0)
	#define ASSERT_NOT_REACHABLE() ((void)0)

#else /* debugging enabled */

	#define ASSERT(x)                                                                                                  \
		if (!(x)) {                                                                                                    \
			PANIC("Null Value ( " #x " )");                                                                            \
		}
	#define ASSERT_NOT_REACHABLE() PANIC("Not Reachable Line")

#endif<file_sep>/kernel/Utils/CircularBuffer.h
#pragma once

#include "Utils/Stl.h"
#include "Utils/Types.h"
#ifdef __UNIT_TESTS
	#include <assert.h>
	#define ASSERT(x) assert(x)
#else
	#include "Assert.h"
#endif
template <typename T> class CircularBuffer
{
  private:
	T* m_data;
	size_t m_head;
	size_t m_tail;
	size_t m_size;
	const size_t m_capacity;

  public:
	explicit CircularBuffer(const size_t size);
	void queue(const T&);
	void queue(T&&);
	T dequeue();
	T& front();
	T& back();
	bool is_empty();
	bool is_full();
	size_t capacity();
	size_t size();
	size_t available_size();
	~CircularBuffer();
};

template <typename T>
CircularBuffer<T>::CircularBuffer(const size_t size) :
    m_data{new T[size]}, //
    m_head{0},
    m_tail{0},
    m_size{0},
    m_capacity{size}
{
}

template <typename T> void CircularBuffer<T>::queue(const T& data_to_queue)
{
	ASSERT(!is_full());
	m_data[m_tail] = data_to_queue;
	m_tail = (m_tail + 1) % m_capacity;
	m_size++;
}

template <typename T> void CircularBuffer<T>::queue(T&& data_to_queue)
{
	ASSERT(!is_full());
	m_data[m_tail] = move(data_to_queue);
	m_tail = (m_tail + 1) % m_capacity;
	m_size++;
}

template <typename T> T CircularBuffer<T>::dequeue()
{
	ASSERT(!is_empty());
	T ret_data = move(m_data[m_head]);
	m_data[m_head].~T();
	m_head = (m_head + 1) % m_capacity;
	m_size--;
	return ret_data;
}

template <typename T> T& CircularBuffer<T>::front()
{
	return m_data[m_head];
}

template <typename T> T& CircularBuffer<T>::back()
{
	return m_data[m_tail - 1];
}

template <typename T> CircularBuffer<T>::~CircularBuffer()
{
	for (size_t i = m_head; i < m_tail; i++) {
		m_data[i].~T();
	}
	operator delete(m_data);
}

template <typename T> bool CircularBuffer<T>::is_empty()
{
	return m_size == 0;
}

template <typename T> bool CircularBuffer<T>::is_full()
{
	return m_size == m_capacity;
}

template <typename T> size_t CircularBuffer<T>::capacity()
{
	return m_capacity;
}

template <typename T> size_t CircularBuffer<T>::size()
{
	return m_size;
}

template <typename T> size_t CircularBuffer<T>::available_size()
{
	return capacity() - size();
}<file_sep>/kernel/Arch/x86/Asm.h
#pragma once
#include "Utils/Types.h"

#define JMP(x)               asm("JMP *%0" : : "r"(kernel_init) :)
#define CALL(x, arg)         asm volatile("PUSH %0;CALL %1;" : : "r"(arg), "r"(x));
#define HLT()                asm("HLT")
#define DISABLE_INTERRUPTS() asm("CLI")
#define ENABLE_INTERRUPTS()  asm("STI")
#define SET_STACK(x)         asm("MOV %%ESP,%0; SUB %%esp,0x10" : : "r"(x) :) // PUSH for the debuggers to work properly.

static inline uint32_t get_faulted_page()
{
	uint32_t page;
	asm("MOV %0,%%CR2" : "=r"(page));
	return page;
}

static inline uint8_t in8(uint16_t port)
{
	uint8_t data;
	asm volatile("inb %0, %1" : "=a"(data) : "d"(port));
	return data;
}

static inline uint16_t in16(uint16_t port)
{
	uint16_t data;
	asm volatile("inw %0, %1" : "=a"(data) : "d"(port));
	return data;
}

static inline uint32_t in32(uint16_t port)
{
	uint32_t data;
	asm volatile("inl %0, %1" : "=a"(data) : "d"(port));
	return data;
}

static inline void out8(uint16_t port, uint8_t data)
{
	asm volatile("outb %1, %0" : : "a"(data), "d"(port));
}

static inline void out16(uint16_t port, uint16_t data)
{
	asm volatile("outw %1, %0" ::"a"(data), "d"(port));
}

static inline void out32(uint16_t port, uint32_t data)
{
	asm volatile("outl %1, %0" : : "a"(data), "d"(port));
}

static inline uint32_t test_and_set(volatile uint32_t* address)
{
	uint32_t result;
	asm volatile(" LOCK XCHG %1, %0\n" : "+m"(*address), "=a"(result) : "1"(1) : "cc", "memory");
	return result;
}

static inline uint32_t eflags_read()
{
	uint32_t eflags;
	asm volatile("PUSHF\n"
	             "POP %0\n"
	             : "=r"(eflags));

	return eflags;
}

static inline void eflags_write(uint32_t eflags)
{
	asm volatile("PUSH %0\n"
	             "POPF \n" ::"r"(eflags));
}<file_sep>/kernel/Tasking/SpinLock.h
#pragma once

#include "Arch/x86/Spinlock.h"

class Spinlock : public StaticSpinlock
{
  public:
	Spinlock() : StaticSpinlock{}
	{
		init();
	}
	~Spinlock() = default;
};
<file_sep>/kernel/CMakeLists.txt
include_directories(".")

#set(CMAKE_CXX_STANDARD 17)
SET(GCC_COVERAGE_COMPILE_FLAGS "-m32 -masm=intel -g -Wall -Wextra --std=c++17 -Og -MMD -fno-pie -ffreestanding -fno-rtti -fno-exceptions -fno-leading-underscore -Werror=return-type")
SET(GCC_COVERAGE_LINK_FLAGS    "-T ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld -m32 -nostdlib")
SET(CMAKE_CXX_FLAGS  ${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS})
SET(CMAKE_EXE_LINKER_FLAGS  ${CMAKE_EXE_LINKER_FLAGS} ${GCC_COVERAGE_LINK_FLAGS})

file(GLOB_RECURSE SOURCES "*.cpp" "*.asm")
add_executable(${OUTPUT_FILE} ${SOURCES})
add_custom_command(
    TARGET ${OUTPUT_FILE}
    POST_BUILD
    COMMAND ${CMAKE_OBJCOPY} ARGS -O binary $<TARGET_FILE_NAME:${OUTPUT_FILE}> ${OUTPUT_IMAGE}
    COMMENT "Striping the kernel output file..."
)
<file_sep>/kernel/Arch/x86/Paging.cpp
#include "Paging.h"

PAGE_DIRECTORY Paging::page_direcotry __attribute__((aligned(PAGE_SIZE)));
PAGE_TABLE Paging::kernel_page_tables[FULL_KERNEL_PAGES] __attribute__((aligned(PAGE_SIZE)));
PAGE_TABLE Paging::boostrap_page_table[2] __attribute__((aligned(PAGE_SIZE)));

// Initialize page direcotry and page tables.
void Paging::setup(uint32_t num_kernel_pages)
{
	PAGE_DIRECTORY* ph_page_direcotry = (PAGE_DIRECTORY*)VIR_TO_PHY((uint32_t)&page_direcotry);
	initialize_page_directory(ph_page_direcotry);
	// Link to page tables
	setup_page_tables();
	// Map identity and higher half
	map_boot_pages(KERNEL_PHYSICAL_ADDRESS, KERNEL_PHYSICAL_ADDRESS, num_kernel_pages);
	map_boot_pages(KERNEL_VIRTUAL_ADDRESS, KERNEL_PHYSICAL_ADDRESS, num_kernel_pages);
	// Load page directory and enable paging
	load_page_directory((uint32_t)ph_page_direcotry);
	enable_PSE();
	enable_paging();
}

void Paging::setup_page_tables()
{
	PAGE_DIRECTORY* ph_page_direcotry = (PAGE_DIRECTORY*)VIR_TO_PHY((uint32_t)&page_direcotry);
	PAGE_TABLE* ph_kpage_tables = (PAGE_TABLE*)VIR_TO_PHY((uint32_t)kernel_page_tables);
	PAGE_TABLE* ph_bootpage_tables = (PAGE_TABLE*)VIR_TO_PHY((uint32_t)boostrap_page_table);
	uint32_t page_flags = PAGE_FLAGS_PRESENT | PAGE_FLAGS_WRITABLE;
	initialize_page_directory(ph_page_direcotry);
	// Kernel pages tables
	for (size_t i = 0; i < FULL_KERNEL_PAGES; i++) {
		initialize_page_table(&ph_kpage_tables[i]);
		fill_directory_entry(&ph_page_direcotry->entries[i + GET_PDE_INDEX(KERNEL_BASE)],
		                     GET_FRAME((uint32_t)&ph_kpage_tables[i]), page_flags);
	}
	// Identity page tables for 8mb of the kernel bootstrap
	for (size_t i = 0; i < 2; i++) {
		initialize_page_table(&ph_bootpage_tables[i]);
		fill_directory_entry(&ph_page_direcotry->entries[i], GET_FRAME((uint32_t)&ph_bootpage_tables[i]), page_flags);
	}
	// Set recursive entry
	fill_directory_entry(&ph_page_direcotry->entries[RECURSIVE_ENTRY], GET_FRAME((uint32_t)ph_page_direcotry),
	                     page_flags);
}
// Map virtual address range to physical address, can be used only at boot time.
void Paging::map_boot_pages(uint32_t virtual_address, uint32_t physical_address, uint32_t pages)
{
	PAGE_DIRECTORY* ph_page_directory = (PAGE_DIRECTORY*)VIR_TO_PHY((uint32_t)&page_direcotry);
	uint32_t current_v_page = virtual_address;
	uint32_t current_p_page = physical_address;
	uint32_t page_flags = PAGE_FLAGS_PRESENT | PAGE_FLAGS_WRITABLE | PAGE_FLAGS_GLOBAL;
	for (size_t i = 0; i < pages; i++) {
		uint32_t pde = GET_PDE_INDEX(current_v_page);
		uint32_t pte = GET_PTE_INDEX(current_v_page);
		PAGE_TABLE* ph_page_table = (PAGE_TABLE*)(ph_page_directory->entries[pde].frame * PAGE_SIZE);
		fill_page_table_entry(&ph_page_table->entries[pte], GET_FRAME(current_p_page), page_flags);
		current_v_page += PAGE_SIZE;
		current_p_page += PAGE_SIZE;
	}
}

// Map a virtual page to a physical page.
void Paging::map_page(uint32_t virtual_address, uint32_t physical_address, uint32_t flags)
{
	PAGE_TABLE* page_table = (PAGE_TABLE*)GET_PAGE_VIRTUAL_ADDRESS(RECURSIVE_ENTRY, GET_PDE_INDEX(virtual_address));
	fill_page_table_entry(&page_table->entries[GET_PTE_INDEX(virtual_address)], GET_FRAME(physical_address), flags);
	invalidate_page(virtual_address);
}

// Map contagious virtual pages to contagious physical pages.
void Paging::map_pages(uint32_t virtual_address, uint32_t physical_address, uint32_t pages, uint32_t flags)
{
	for (size_t i = 0; i < pages; i++) {
		map_page(virtual_address + PAGE_SIZE * i, physical_address + PAGE_SIZE * i, flags);
	}
}

// Map a virtual page to a physical page.
void Paging::unmap_page(uint32_t virtual_address)
{
	PAGE_TABLE* page_table = (PAGE_TABLE*)GET_PAGE_VIRTUAL_ADDRESS(RECURSIVE_ENTRY, GET_PDE_INDEX(virtual_address));
	page_table->entries[GET_PTE_INDEX(virtual_address)].present = 0;
	invalidate_page(virtual_address);
}

// Map contagious virtual pages to contagious physical pages.
void Paging::unmap_pages(uint32_t virtual_address, uint32_t pages)
{
	for (size_t i = 0; i < pages; i++) {
		unmap_page(virtual_address + PAGE_SIZE * i);
	}
}

void Paging::map_page_table(uint32_t virtual_address, uint32_t pt_virtual_address)
{
	uint32_t page_flags = PAGE_FLAGS_PRESENT | PAGE_FLAGS_WRITABLE | PAGE_FLAGS_USER;
	PAGE_DIRECTORY* page_dir = (PAGE_DIRECTORY*)GET_PAGE_VIRTUAL_ADDRESS(RECURSIVE_ENTRY, RECURSIVE_ENTRY);
	uint32_t pt_frame = get_physical_page(pt_virtual_address);
	fill_directory_entry(&page_dir->entries[GET_PDE_INDEX(virtual_address)], pt_frame, page_flags);
}

bool Paging::check_page_table_exists(uint32_t virtual_address)
{
	PAGE_DIRECTORY* page_dir = (PAGE_DIRECTORY*)GET_PAGE_VIRTUAL_ADDRESS(RECURSIVE_ENTRY, RECURSIVE_ENTRY);
	return page_dir->entries[GET_PDE_INDEX(virtual_address)].present;
}

bool Paging::check_page_exits_in_table(uint32_t virtual_address)
{
	PAGE_TABLE* page_table = (PAGE_TABLE*)GET_PAGE_VIRTUAL_ADDRESS(RECURSIVE_ENTRY, GET_PDE_INDEX(virtual_address));
	return page_table->entries[GET_PTE_INDEX(virtual_address)].present;
}

bool Paging::check_page_present(uint32_t virtual_address)
{
	if (check_page_table_exists(virtual_address) == false)
		return false;
	return check_page_exits_in_table(virtual_address);
}

uint32_t Paging::get_physical_page(uint32_t virtual_address)
{
	PAGE_TABLE* page_table = (PAGE_TABLE*)GET_PAGE_VIRTUAL_ADDRESS(RECURSIVE_ENTRY, GET_PDE_INDEX(virtual_address));
	return page_table->entries[GET_PTE_INDEX(virtual_address)].frame;
}

// Zeroing page directory entries.
void Paging::initialize_page_directory(PAGE_DIRECTORY* page_direcotry)
{
	for (size_t i = 0; i < NUMBER_OF_PAGE_DIRECOTRY_ENTRIES; i++) {
		*((uint32_t*)&page_direcotry->entries[i]) = 0;
	}
}

// Zeroing page table entries.
void Paging::initialize_page_table(PAGE_TABLE* page_direcotry)
{
	for (size_t i = 0; i < NUMBER_OF_PAGE_TABLE_ENTRIES; i++) {
		*((uint32_t*)&page_direcotry->entries[i]) = 0;
	}
}

void Paging::map_kernel_pd_entries(uint32_t pd)
{
	uint32_t page_flags = PAGE_FLAGS_PRESENT | PAGE_FLAGS_WRITABLE;
	PAGE_DIRECTORY* new_page_dir = (PAGE_DIRECTORY*)pd;
	initialize_page_directory(new_page_dir);
	const size_t start = GET_PDE_INDEX(KERNEL_VIRTUAL_ADDRESS);
	for (size_t i = start; i < RECURSIVE_ENTRY; i++) {
		memcpy((void*)&new_page_dir->entries[i], (void*)&page_direcotry.entries[i], sizeof(PAGE_DIRECTORY_ENTRY));
	}
	fill_directory_entry(&new_page_dir->entries[RECURSIVE_ENTRY], get_physical_page(pd), page_flags);
}

void Paging::fill_directory_entry(PAGE_DIRECTORY_ENTRY* page_direcotry_entry, uint16_t physical_frame, uint32_t flags)
{
	page_direcotry_entry->unused = 0;
	page_direcotry_entry->global = BOOL(flags & PAGE_FLAGS_GLOBAL);
	page_direcotry_entry->pwt = 0;
	page_direcotry_entry->pcd = 0;
	page_direcotry_entry->pse = 0;
	page_direcotry_entry->present = BOOL(flags & PAGE_FLAGS_PRESENT);
	page_direcotry_entry->rw = BOOL(flags & PAGE_FLAGS_WRITABLE);
	page_direcotry_entry->user = BOOL(flags & PAGE_FLAGS_USER);
	page_direcotry_entry->frame = physical_frame;
}

void Paging::fill_directory_PSE_entry(PAGE_DIRECTORY_ENTRY* page_direcotry_entry, uint16_t physical_frame,
                                      uint32_t flags)
{
	page_direcotry_entry->unused = 0;
	page_direcotry_entry->global = BOOL(flags & PAGE_FLAGS_GLOBAL);
	page_direcotry_entry->pwt = 0;
	page_direcotry_entry->pcd = 0;
	page_direcotry_entry->pse = 1;
	page_direcotry_entry->present = BOOL(flags & PAGE_FLAGS_PRESENT);
	page_direcotry_entry->rw = BOOL(flags & PAGE_FLAGS_WRITABLE);
	page_direcotry_entry->user = BOOL(flags & PAGE_FLAGS_USER);
	page_direcotry_entry->frame = physical_frame;
}

void Paging::fill_page_table_entry(PAGE_TABLE_ENTRY* page_table_entry, uint16_t physical_frame, uint32_t flags)
{
	// FIXME: accessing bits directly is so slow.
	page_table_entry->unused = 0;
	page_table_entry->global = BOOL(flags & PAGE_FLAGS_GLOBAL);
	page_table_entry->pwt = 0;
	page_table_entry->pcd = 0;
	page_table_entry->pse = 0;
	page_table_entry->present = BOOL(flags & PAGE_FLAGS_PRESENT);
	page_table_entry->rw = BOOL(flags & PAGE_FLAGS_WRITABLE);
	page_table_entry->user = BOOL(flags & PAGE_FLAGS_USER);
	page_table_entry->frame = physical_frame;
}

void Paging::load_page_directory(uint32_t page_direcotry)
{
	asm("MOV %%CR3,%0" : : "r"(page_direcotry) :);
}

void Paging::enable_paging()
{
	asm("MOV %%EAX,%%CR0;"
	    "OR  %%EAX,%0;"
	    "MOV %%CR0,%%EAX ;"
	    :
	    : "i"(CR0_WP | CR0_PAGING)
	    : "eax");
}

void Paging::enable_PSE()
{
	asm("MOV %%EAX,%%CR4;"
	    "OR %%EAX,%0;"
	    "MOV %%CR4,%%EAX;"
	    :
	    : "i"(CR4_PSE)
	    : "eax");
}

void Paging::invalidate_page(uint32_t addr)
{
	asm volatile("invlpg [%0]" ::"r"(addr) : "memory");
}<file_sep>/kernel/Lib/Malloc.cpp
#include "Arch/x86/Panic.h"
#include "Utils/Types.h"
#include "VirtualMemory/Heap.h"

void* operator new(size_t size)
{
	return Heap::kmalloc(size, 0);
}

void* operator new[](size_t size)
{
	return Heap::kmalloc(size, 0);
}

void operator delete(void* p)
{
	return Heap::kfree(p);
}

void operator delete[](void* p)
{
	return Heap::kfree(p);
}

void* operator new(size_t, void* p)
{
	return p;
}

void* operator new[](size_t, void* p)
{
	return p;
}

void operator delete[](void* p, size_t)
{
	Heap::kfree(p);
}
void operator delete(void* p, size_t)
{
	Heap::kfree(p);
}

extern "C" void __cxa_pure_virtual()
{
	PANIC("Virtual function has no implementation!");
}<file_sep>/test/IntrusiveList.cpp
#ifdef __STRICT_ANSI__
	#undef __STRICT_ANSI__
#endif

#include "Utils/IntrusiveList.h"
#include <gtest/gtest.h>

struct TestStruct : public IntrusiveListNode<TestStruct> {
	int a;
	int b;
	bool operator==(const TestStruct& other)
	{
		if (a != other.a)
			return false;
		if (b != other.b)
			return false;
		return true;
	}
	TestStruct(int aa, int bb) : a{aa}, b{bb}
	{
	}
};

TEST(IntrusiveList_Test, Iteration)
{
	TestStruct raw_list[] = {{1, 2}, {3, 4}, {5, 6}};
	IntrusiveList<TestStruct> list;
	for (size_t i = 0; i < 3; i++) {
		list.push_back(raw_list[i]);
	}

	EXPECT_EQ(list.size(), 3);

	size_t index = 0;
	for (auto&& i : list) {
		EXPECT_TRUE(i == raw_list[index]);
		index++;
	}
}

TEST(IntrusiveList_Test, Removing)
{
	/*TestStruct raw_list[] = {{1, 2}, {3, 4}, {5, 6}};
	IntrusiveList<TestStruct> list;
	for (size_t i = 0; i < 3; i++) {
	    list.push_back(raw_list[i]);
	}

	EXPECT_EQ(list.size(), 3);

	list.remove(1);
	EXPECT_EQ(list.size(), 2);
	EXPECT_TRUE(list[0] == raw_list[0]);
	EXPECT_TRUE(list[1] == raw_list[2]);

	list.remove(1);
	EXPECT_EQ(list.size(), 1);
	EXPECT_TRUE(list[0] == raw_list[0]);

	list.remove(0);
	EXPECT_EQ(list.size(), 0);*/
}

TEST(IntrusiveList_Test, MovingBetweenLists)
{
	/*TestStruct raw_list1[] = {{1, 2}, {3, 4}, {5, 6}};
	TestStruct raw_list2[] = {{10, 20}, {30, 40}, {50, 60}, {70, 80}};
	IntrusiveList<TestStruct> list1;
	IntrusiveList<TestStruct> list2;
	for (size_t i = 0; i < 3; i++) {
	    list1.push_back(raw_list1[i]);
	}
	for (size_t i = 0; i < 4; i++) {
	    list2.push_back(raw_list2[i]);
	}

	EXPECT_EQ(list1.size(), 3);
	EXPECT_EQ(list2.size(), 4);

	list2.move_head_to_other_list(&list1);

	EXPECT_EQ(list1.size(), 4);
	EXPECT_EQ(list2.size(), 3);
	EXPECT_TRUE(list1[3] == raw_list2[0]);

	auto itr{list2.begin()};
	itr.move_cursor(2);
	list2.move_to_other_list(&list1, itr);

	EXPECT_EQ(list1.size(), 5);
	EXPECT_EQ(list2.size(), 2);
	EXPECT_TRUE(list1[4] == raw_list2[3]);*/
}<file_sep>/test/List_Test.cpp
#ifdef __STRICT_ANSI__
	#undef __STRICT_ANSI__
#endif
#include "Utils/List.h"
#include <gtest/gtest.h>

struct TestStruct {
	int a;
	int b;
	bool operator==(const TestStruct& other)
	{
		if (a != other.a)
			return false;
		if (b != other.b)
			return false;
		return true;
	}
};

TEST(List_Test, Iteration)
{
	TestStruct raw_list[] = {{1, 2}, {3, 4}, {5, 6}};
	List<TestStruct> list;
	for (size_t i = 0; i < 3; i++) {
		list.push_back(raw_list[i]);
	}

	EXPECT_EQ(list.size(), 3);
	EXPECT_FALSE(list.is_empty());

	size_t index = 0;
	for (auto&& i : list) {
		EXPECT_TRUE(i == raw_list[index]);
		index++;
	}
}

TEST(List_Test, Erasing)
{
	TestStruct raw_list[] = {{1, 2}, {3, 4}, {5, 6}};
	List<TestStruct> list;
	for (size_t i = 0; i < 3; i++) {
		list.push_back(raw_list[i]);
	}

	EXPECT_EQ(list.size(), 3);
	EXPECT_FALSE(list.is_empty());

	list.erase(++list.begin());
	EXPECT_EQ(list.size(), 2);
	EXPECT_TRUE(list[0] == raw_list[0]);
	EXPECT_TRUE(list[1] == raw_list[2]);

	list.erase(++list.begin());
	EXPECT_EQ(list.size(), 1);
	EXPECT_TRUE(list[0] == raw_list[0]);

	list.erase(list.begin());
	EXPECT_EQ(list.size(), 0);
	EXPECT_TRUE(list.is_empty());

	for (size_t i = 0; i < 3; i++) {
		list.push_back(raw_list[i]);
	}
	EXPECT_EQ(list.size(), 3);
	EXPECT_FALSE(list.is_empty());

	list.clear();

	EXPECT_EQ(list.size(), 0);
	EXPECT_TRUE(list.is_empty());
}

TEST(List_Test, Splicing)
{
	TestStruct raw_list1[] = {{1, 2}, {3, 4}, {5, 6}};
	TestStruct raw_list2[] = {{10, 20}, {30, 40}, {50, 60}, {70, 80}};
	List<TestStruct> list1;
	List<TestStruct> list2;
	for (size_t i = 0; i < 3; i++) {
		list1.push_back(raw_list1[i]);
	}
	for (size_t i = 0; i < 4; i++) {
		list2.push_back(raw_list2[i]);
	}

	EXPECT_EQ(list1.size(), 3);
	EXPECT_EQ(list2.size(), 4);
	EXPECT_FALSE(list1.is_empty());
	EXPECT_FALSE(list2.is_empty());

	list2.splice(list1, list2.begin());

	EXPECT_EQ(list1.size(), 4);
	EXPECT_EQ(list2.size(), 3);
	EXPECT_TRUE(list1[3] == raw_list2[0]);

	auto itr{list2.begin()};
	itr++;
	itr++;
	list2.splice(list1, itr);

	EXPECT_EQ(list1.size(), 5);
	EXPECT_EQ(list2.size(), 2);
	EXPECT_TRUE(list1[4] == raw_list2[3]);
	EXPECT_FALSE(list1.is_empty());
	EXPECT_FALSE(list2.is_empty());
}

TEST(List_Test, Inserting)
{
	List<TestStruct> list;
	list.emplace_back(1, 1);
	list.emplace_front(2, 2);
	list.emplace_back(3, 3);
	EXPECT_TRUE(list[0] == TestStruct({2, 2}));
	EXPECT_TRUE(list[1] == TestStruct({1, 1}));
	EXPECT_TRUE(list[2] == TestStruct({3, 3}));
	EXPECT_EQ(list.size(), 3);

	list.insert(++list.begin(), TestStruct({4, 4}));

	EXPECT_TRUE(list[0] == TestStruct({2, 2}));
	EXPECT_TRUE(list[1] == TestStruct({1, 1}));
	EXPECT_TRUE(list[2] == TestStruct({4, 4}));
	EXPECT_TRUE(list[3] == TestStruct({3, 3}));
	EXPECT_EQ(list.size(), 4);

	EXPECT_TRUE(list.head() == TestStruct({2, 2}));
	EXPECT_TRUE(list.tail() == TestStruct({3, 3}));
}<file_sep>/kernel/Utils/ErrorCodes.h
#pragma once

#define ERROR_SUCCESS               0
#define ERROR_UNDEFINED             1
#define ERROR_FILE_DOES_NOT_EXIST   2
#define ERROR_MOUNTPOINT_EXISTS     3
#define ERROR_EOF                   4
#define ERROR_INVALID_PARAMETERS    5
#define ERROR_INVALID_EXECUTABLE    6
#define ERROR_LOADING_EXECUTABLE    7
#define ERROR_NO_ROOT_NODE          8
#define ERROR_INVALID_OPERATION     9
#define ERROR_FILE_ALREADY_EXISTS   10
#define ERROR_DEVICE_ALREADY_EXISTS 11
#define ERROR_DEVICE_DOESNOT_EXIST  12
#define ERROR_FS_ALREADY_EXISTS     13
<file_sep>/kernel/Lib/Stdlib.h
#pragma once
#include "Utils/Types.h"

void memcpy(void* dest, const void* source, unsigned int len);
void memset(void* dest, char value, unsigned int len);
bool memcmp(const void* source, const void* dest, unsigned int len);
bool strncmp(const char* source, const char* dest, unsigned int len);
bool strcmp(const char* source, const char* dest);
int strcpy(char* dst, const char* src);
unsigned strlen(const char* str);
int toupper(char* str);
int tolower(char* str);
void itoa(char* buf, unsigned long int n, int base);<file_sep>/kernel/VirtualMemory/Heap.cpp
#include "Heap.h"
#include "Tasking/ScopedLock.h"

volatile PageFrameBlock* Heap::malloc_mem;
StaticSpinlock Heap::lock;

void Heap::setup()
{
	lock.init();
	malloc_mem = nullptr;
	malloc_mem = create_new_page();
}

// Returns address of zeroed block of memory.
void* Heap::kmalloc(unsigned size, unsigned flags)
{
	UNUSED(flags);
	ScopedLock local_lock(lock);
	// FIXME: allocate normal memory if the size is greater than MAX_SIZE (there is a bug when less) and handle
	// freeing too
	if (!size)
		return nullptr;

	if (size > MAX_SIZE) {
		return nullptr;
	}

	BlockHeader* free_block;
	// Check if there is a free block in the list
	// TODO: if the current page is not enough, try expanding it by allocating neighbor pages.
	// TODO: classify the sizes into power of 2 sizes.
	free_block = find_free_block(size + sizeof(BlockHeader));
	if (free_block) {
		link_block(free_block->previous, free_block);
		free_block->size = size;
		return (void*)HEADER_TO_ADDR(free_block);
	}
	// Create new memory page
	PageFrameBlock* new_page = create_new_page();
	free_block = initiate_first_block(new_page);
	free_block->size = size;
	uintptr_t alloc_address = HEADER_TO_ADDR(free_block);
	memset((void*)alloc_address, 0, size);
	return (void*)alloc_address;
}

// Frees block of memory allocated by kmalloc.
void Heap::kfree(void* addr)
{
	if (!addr)
		return;

	ScopedLock local_lock(lock);
	BlockHeader* current_block = (BlockHeader*)ADDR_TO_HEADER(addr);
	unlink_block(current_block);
}

PageFrameBlock* Heap::create_new_page()
{
	// FIXME: create page according to the allocation size.
	// FIXME: do some asserts to nullpointers.
	PageFrameBlock* new_page =
	    (PageFrameBlock*)Memory::alloc(MALLOC_PAGE_SIZE, MEMORY_TYPE::KERNEL | MEMORY_TYPE::WRITABLE);
	new_page->size = MALLOC_PAGE_SIZE;

	PageFrameBlock* last_page = get_last_page();
	if (last_page) {
		last_page->next = new_page;
	}
	return new_page;
}

BlockHeader* Heap::initiate_first_block(PageFrameBlock* new_page)
{
	BlockHeader* empty_block = (BlockHeader*)(new_page + 1);
	BlockHeader* free_block = (empty_block + 1);
	empty_block->size = 0;
	empty_block->previous = 0;
	empty_block->next = free_block;
	free_block->previous = empty_block;
	return free_block;
}

void Heap::link_block(BlockHeader* current_block, BlockHeader* new_block)
{
	BlockHeader* prev_block = current_block;
	BlockHeader* next_block = current_block->next;
	prev_block->next = new_block;
	if (next_block)
		next_block->previous = new_block;
}

void Heap::unlink_block(BlockHeader* current_block)
{
	BlockHeader* prev_block = current_block->previous;
	BlockHeader* next_block = current_block->next;
	prev_block->next = next_block;
	if (next_block) {
		next_block->previous = prev_block;
	}
}

BlockHeader* Heap::find_free_block(unsigned size)
{
	volatile PageFrameBlock* current_page = malloc_mem;
	BlockHeader *current_block, *free_block;
	unsigned current_free_space;
	while (current_page) {
		current_block = (BlockHeader*)(current_page + 1);
		while (current_block) {
			if (current_block->next) {
				current_free_space = (unsigned)current_block->next - NEXT_NEIGHBOR_BLOCK(current_block);
			} else { // last block in the current page
				current_free_space = (unsigned)current_page + current_page->size - NEXT_NEIGHBOR_BLOCK(current_block);
			}
			if (current_free_space >= size) {
				free_block = (BlockHeader*)NEXT_NEIGHBOR_BLOCK(current_block);
				free_block->previous = current_block;
				free_block->next = current_block->next;
				return free_block;
			}

			current_block = current_block->next;
		}
		current_page = current_page->next;
	}
	return nullptr;
}

PageFrameBlock* Heap::get_last_page()
{
	if (!malloc_mem) {
		return nullptr;
	}
	volatile PageFrameBlock* current = malloc_mem;
	while (current->next) {
		current = current->next;
	}
	return (PageFrameBlock*)current;
}<file_sep>/kernel/Boot/Boot.cpp

#include "Boot.h"
#include "Devices/DebugPort/Logger.h"

extern uint32_t KERNEL_END;
extern uint32_t KERNEL_START;
BootloaderInfo bootloader_info;
__attribute__((section(".multiboot2"))) const volatile Mutiboot2_Header my_multiboot2_header = {
    .header = {.magic = MULTIBOOT2_HEADER_MAGIC,
               .architecture = MULTIBOOT_ARCHITECTURE_I386,
               .header_length = sizeof(Mutiboot2_Header),
               .checksum = MULTIBOOT2_HEADER_CHECKSUM},
    .address = {.type = MULTIBOOT_HEADER_TAG_ADDRESS,
                .flags = 0,
                .size = sizeof(multiboot_header_tag_address),
                .header_addr = VIR_TO_PHY((uint32_t)&my_multiboot2_header),
                .load_addr = KERNEL_PHYSICAL_ADDRESS,
                .load_end_addr = 0,
                .bss_end_addr = VIR_TO_PHY(uint32_t(&KERNEL_END))},
    .entry = {.type = MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS,
              .flags = 0,
              .size = sizeof(multiboot_header_tag_entry_address),
              .entry_addr = VIR_TO_PHY((uint32_t)&kernel_boot_stage1)},
    .mod_align = {.type = MULTIBOOT_HEADER_TAG_MODULE_ALIGN,
                  .flags = 0,
                  .size = sizeof(multiboot_header_tag_module_align)},
    .end = {.type = MULTIBOOT_HEADER_TAG_END, //
            .flags = 0,
            .size = sizeof(multiboot_header_tag)},
};
extern "C" void kernel_boot_stage2(uint32_t magic, multiboot_tag_start* boot_info)
{

	if (magic != MULTIBOOT2_BOOTLOADER_MAGIC)
		HLT();

	BootloaderInfo bootloader_info_local = parse_mbi((uintptr_t)boot_info);
	Memory::setup();
	// maping ramdisk to virtual memory
	uintptr_t ustar_fs = reinterpret_cast<uintptr_t>(Memory::map(bootloader_info_local.ramdisk.start, //
	                                                             bootloader_info_local.ramdisk.size,  //
	                                                             MEMORY_TYPE::KERNEL | MEMORY_TYPE::WRITABLE));
	bootloader_info_local.ramdisk.start = ustar_fs;
	memcpy(&bootloader_info, &bootloader_info_local, sizeof(BootloaderInfo));
	// Set new stack for high memory kernel.
	uintptr_t new_stack = uintptr_t(Memory::alloc(STACK_SIZE, MEMORY_TYPE::KERNEL | MEMORY_TYPE::WRITABLE));
	SET_STACK(new_stack + STACK_SIZE);
	CALL(kernel_init, &bootloader_info)
	ASSERT_NOT_REACHABLE();
	return;
}

const char* mmap_entry_type_text[] = {"Unknown"           //
                                      "AVAILABLE",        //
                                      "RESERVED",         //
                                      "ACPI_RECLAIMABLE", //
                                      "NVS",              //
                                      "BAD_RAM"};

BootloaderInfo parse_mbi(uintptr_t multiboot_info)
{
	BootloaderInfo bootloader_info_local;

	multiboot_tag* current_tag = (multiboot_tag*)(multiboot_info + sizeof(multiboot_tag_start));
	while (current_tag->type != MULTIBOOT_TAG_TYPE_END) {
		switch (current_tag->type) {
			case MULTIBOOT_TAG_TYPE_MODULE: {
				multiboot_tag_module* tag = (multiboot_tag_module*)current_tag;
				// if (strcmp(tag->cmdline, "ramdisk") == 0) {
				bootloader_info_local.ramdisk.start = tag->mod_start;
				bootloader_info_local.ramdisk.size = tag->mod_end - tag->mod_start;
				//}
				break;
			}
			case MULTIBOOT_TAG_TYPE_MMAP: {
				multiboot_tag_mmap* tag2 = (multiboot_tag_mmap*)current_tag;
				size_t i = 0;
				// info() << "Memory Map:\n";
				while (tag2->entries[i].type != 0) {
					// info() << "Addr: " << Hex(tag2->entries[i].addr) << " Size: " << tag2->entries[i].len
					//       << " Type: " << mmap_entry_type_text[tag2->entries[i].type] << "\n";
					i++;
				}
				break;
			}
		}
		current_tag = (multiboot_tag*)(uintptr_t(current_tag) + align_to(current_tag->size, MULTIBOOT_INFO_ALIGN));
	}
	return bootloader_info_local;
}

inline uintptr_t align_to(uintptr_t size, unsigned alignment)
{
	if (size == 0)
		return alignment;
	else if ((size % alignment) == 0)
		return size;
	else
		return size + alignment - (size % alignment);
}<file_sep>/kernel/Filesystem/Ustar/INode.h
#pragma once

#include "Filesystem/FSNode.h"
#include "Tasking/SpinLock.h"
#include "Utils/List.h"
#include "Utils/Result.h"
#include "Utils/String.h"
#include "Utils/Types.h"

class INode : public FSNode
{
  private:
	char* m_data;
	Spinlock m_lock;
	List<INode> m_children;

  public:
	explicit INode(const StringView& name, NodeType type, size_t size, char* data);
	INode& operator=(const INode& other) = delete;
	INode& operator=(INode&& other) = delete;
	~INode();
	Result<void> open(OpenMode mode, OpenFlags flags) override;
	Result<void> close() override;
	Result<void> read(void* buff, size_t offset, size_t size) override;
	Result<bool> can_read() override;
	Result<FSNode&> dir_lookup(const StringView& file_name) override;

	friend class TarFS;
};<file_sep>/kernel/Filesystem/Ustar/TarFS.cpp
#include "TarFS.h"
#include "Tasking/ScopedLock.h"
#include "Utils/ErrorCodes.h"
#include "Utils/Stack.h"
#include "Utils/Stl.h"

UniquePointer<FSNode> TarFS::alloc(const StringView& name, void* tar_address, size_t size)
{
	return UniquePointer<FSNode>(new TarFS(name, tar_address, size));
}

TarFS::TarFS(const StringView& name, void* tar_address, size_t size) :
    INode{name, NodeType::Root, 0, nullptr},
    m_tar_address(static_cast<TarHeader*>(tar_address))
{
	ASSERT(tar_address);
	ASSERT(strncmp(m_tar_address->magic, "ustar", 5) == 0);
	parse_ustar(size);
}

TarFS::~TarFS()
{
}

INode& TarFS::add_child_node(INode& parent, const StringView& name, char type, const size_t size, char* data)
{
	NodeType node_type;
	if (type == USTARFileType::DIRECTORY) {
		node_type = NodeType::Folder;
	} else {
		node_type = NodeType::File;
	}

	return parent.m_children.emplace_back(name, node_type, size, data);
}

void TarFS::parse_ustar(size_t size)
{
	TarHeader* tar_parser = m_tar_address;
	Stack<INode*> directories(10);
	directories.queue(this);

	while (uintptr_t(tar_parser) < (uintptr_t(m_tar_address) + size)) {
		if (!tar_parser->name[0])
			break;
		String path = regulate_path(tar_parser->name);
		PathParser parser = PathParser(StringView(path));

		if (parser.count() > 1) {
			while (directories.back()->m_name != (parser.element(parser.count() - 2)) && (directories.size() > 1)) {
				directories.dequeue();
			}
		} else {
			while (directories.size() > 1) {
				directories.dequeue();
			}
		}

		auto& new_node = add_child_node(
		    *directories.back(),                //
		    parser.element(parser.count() - 1), //
		    tar_parser->typeflag,               //
		    octal_to_decimal(tar_parser->size), //
		    tar_parser->typeflag != USTARFileType::DIRECTORY ? reinterpret_cast<char*>(tar_parser + 1) : nullptr);

		if (tar_parser->typeflag == USTARFileType::DIRECTORY) {
			directories.queue(&new_node);
		}
		const uintptr_t aligned_size = align_to(octal_to_decimal(tar_parser->size), TAR_ALIGNMENT);
		tar_parser = (TarHeader*)(uintptr_t(tar_parser + 1) + aligned_size);
	}
}

size_t TarFS::octal_to_decimal(const char* octal)
{
	size_t size = 0;
	unsigned current_multiplier = 1;
	for (size_t i = TAR_OCTAL_SIZE_LEN - 1; i > 0; i--) {
		size += (octal[i - 1] - '0') * current_multiplier;
		current_multiplier *= 8;
	}
	return size;
}

inline uintptr_t TarFS::align_to(uintptr_t size, unsigned alignment)
{
	if (!size)
		return 0;
	else if ((size % alignment) == 0)
		return size;
	else
		return size + alignment - (size % alignment);
}

String TarFS::regulate_path(const char* path)
{
	String full_path(path);
	full_path.insert(0, "/");
	if (full_path[full_path.length() - 1] == '/') {
		full_path.pop_back();
	}

	return full_path;
}

Result<FSNode&> TarFS::dir_lookup(const StringView& file_name)
{
	ScopedLock local_lock(m_lock);
	for (auto& i : m_children) {
		if (i.m_name == file_name) {
			return i;
		}
	}
	return ResultError(ERROR_FILE_DOES_NOT_EXIST);
}
<file_sep>/kernel/Filesystem/Pipes/Pipe.h
#pragma once

#include "Filesystem/FSNode.h"
#include "Tasking/WaitQueue.h"
#include "Utils/CircularBuffer.h"
#include "Utils/List.h"
#include "Utils/String.h"
#include "Utils/StringView.h"
#include "Utils/UniquePointer.h"
#include "Utils/Types.h"

class Pipe : public FSNode
{
	enum class Direction { Reader, Writer };

  private:
	const static size_t BUFFER_SIZE = 1024;
	List<Pipe> m_children;
	CircularBuffer<char> m_buffer;
	WaitQueue m_wait_queue;
	Spinlock m_lock;

  public:
	explicit Pipe(const StringView& name);
	~Pipe();
	Result<void> open(OpenMode mode, OpenFlags flags) override;
	Result<void> close() override;
	Result<void> read(void* buff, size_t offset, size_t size) override;
	Result<void> write(const void* buff, size_t offset, size_t size) override;
	Result<bool> can_read() override;
	Result<bool> can_write() override;
	Result<void> remove() override;
};<file_sep>/kernel/Tasking/Loader/PE.cpp
#include "PE.h"
#include "Lib/Stdlib.h"
#include "Utils/ErrorCodes.h"
#include "VirtualMemory/Memory.h"

Result<uintptr_t> PELoader::load(const char* file, size_t size)
{
	ASSERT(file);
	ASSERT(size);
	// validations
	const IMAGE_DOS_HEADER* dos_header = reinterpret_cast<const IMAGE_DOS_HEADER*>(file);
	if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
		return ResultError(ERROR_INVALID_EXECUTABLE);
	if (!dos_header->e_lfanew)
		return ResultError(ERROR_INVALID_EXECUTABLE);

	const IMAGE_NT_HEADERS32* nt_header = reinterpret_cast<const IMAGE_NT_HEADERS32*>(file + dos_header->e_lfanew);
	if (nt_header->Signature != IMAGE_NT_SIGNATURE)
		return ResultError(ERROR_INVALID_EXECUTABLE);

	const IMAGE_SECTION_HEADER* section_header = reinterpret_cast<const IMAGE_SECTION_HEADER*>(nt_header + 1);
	for (size_t i = 0; i < nt_header->FileHeader.NumberOfSections; i++) {
		const uint32_t section_va = section_header[i].VirtualAddress;
		const uint32_t section_rd = section_header[i].PointerToRawData;
		const uint32_t section_raw_size = section_header[i].SizeOfRawData;
		const uint32_t section_vir_size = section_header[i].Misc.VirtualSize;

		if (!section_va || !section_rd || !section_vir_size)
			return ResultError(ERROR_INVALID_EXECUTABLE);

		if ((section_rd + section_raw_size) > size)
			return ResultError(ERROR_INVALID_EXECUTABLE);
	}

	if (!nt_header->OptionalHeader.AddressOfEntryPoint)
		return ResultError(ERROR_INVALID_EXECUTABLE);

	// Load PE sections
	void* start_of_executable = load_pe_sections(file, nt_header);
	if (!start_of_executable)
		return ResultError(ERROR_LOADING_EXECUTABLE);

	return uintptr_t(start_of_executable) + nt_header->OptionalHeader.AddressOfEntryPoint;
}

void* PELoader::load_pe_sections(const char* file, const IMAGE_NT_HEADERS32* nt_header)
{
	const IMAGE_SECTION_HEADER* section_header = reinterpret_cast<const IMAGE_SECTION_HEADER*>(nt_header + 1);
	const uint32_t section_alignment = nt_header->OptionalHeader.SectionAlignment;
	// Load headers
	void* start_of_executable = Memory::alloc(reinterpret_cast<void*>(nt_header->OptionalHeader.ImageBase),
	                                          nt_header->OptionalHeader.SectionAlignment, MEMORY_TYPE::WRITABLE);
	if (!start_of_executable)
		return nullptr;

	memset(start_of_executable, 0, section_alignment);
	memcpy(start_of_executable, file, nt_header->OptionalHeader.SizeOfHeaders);

	// load sections
	for (size_t i = 0; i < nt_header->FileHeader.NumberOfSections; i++) {
		const uint32_t section_va = section_header[i].VirtualAddress;
		const uint32_t section_rd = section_header[i].PointerToRawData;
		const uint32_t section_raw_size = section_header[i].SizeOfRawData;
		const uint32_t section_vir_size = align_to(section_header[i].Misc.VirtualSize, section_alignment);
		void* current_section_address = reinterpret_cast<void*>(uintptr_t(start_of_executable) + section_va);

		current_section_address = Memory::alloc(current_section_address, section_vir_size, MEMORY_TYPE::WRITABLE);
		if (!current_section_address)
			return nullptr;

		memcpy(current_section_address, file + section_rd, section_raw_size);
	}
	return start_of_executable;
}

inline uintptr_t PELoader::align_to(uintptr_t size, size_t alignment)
{
	if (size == 0)
		return alignment;
	else if ((size % alignment) == 0)
		return size;
	else
		return size + alignment - (size % alignment);
}
<file_sep>/kernel/Kernel_init.h
#pragma once
#include "Utils/Types.h"

struct Module {
	uintptr_t start;
	uintptr_t size;
};
struct BootloaderInfo {
	Module ramdisk;
};

extern "C" void kernel_init(BootloaderInfo* boot_info);<file_sep>/kernel/Tasking/Scheduler.cpp
#include "Scheduler.h"
#include "Arch/x86/Asm.h"
#include "Arch/x86/Isr.h"
#include "Devices/Timer/Pit.h"
#include "Filesystem/VirtualFilesystem.h"
#include "Loader/PE.h"
#include "ScopedLock.h"
#include "SystemCall.h"
#include "Utils/Assert.h"
#include "VirtualMemory/Memory.h"

StaticSpinlock Scheduler::lock;

void Scheduler::setup()
{
	lock.init();
	ISR::register_isr_handler(schedule_handler, SCHEDULE_IRQ);
	SystemCall::setup();
	Process::setup();
	Thread::setup();
}

void Scheduler::schedule(ISRContextFrame* current_context, ScheduleType type)
{
	// FIXME: schedule idle if there is no ready thread
	// TODO: move all unnecessary stuff to a separate thread to be performed later.
	ScopedLock local_lock(lock);
	if (type == ScheduleType::TIMED)
		wake_up_sleepers();

	if (Thread::current) {
		save_context(current_context, Thread::current);
	}
	Thread& next_thread = select_next_thread();
	if (Thread::current) {
		if (next_thread.m_parent.m_pid != Thread::current->m_parent.m_pid) {
			switch_page_directory(next_thread.m_parent.m_page_directory);
		}
	} else {
		switch_page_directory(next_thread.m_parent.m_page_directory);
	}
	Thread::current = &next_thread;
	load_context(current_context, &next_thread);
}

Thread& Scheduler::select_next_thread()
{
	static size_t rr_index = 0;
	Thread* next_thread = nullptr;
	size_t threads_index = 0;
	Thread::for_each_ready([&](auto& thread) {
		if (threads_index++ == rr_index % Thread::number_of_ready_threads()) {
			next_thread = &thread;
			return IterationDecision::Break;
		}
		return IterationDecision::Continue;
	});
	ASSERT(Thread::number_of_ready_threads());
	rr_index = (rr_index + 1) % Thread::number_of_ready_threads();
	return *next_thread;
}

void Scheduler::wake_up_sleepers()
{
	Thread::for_each_sleeping([](Thread& thread) {
		if (thread.m_sleep_ticks <= PIT::ticks) {
			thread.m_sleep_ticks = 0;
			thread.wake_up_from_sleep();
		}
		return IterationDecision::Continue;
	});
}

void Scheduler::load_context(ISRContextFrame* current_context, const Thread* thread)
{
	current_context->context_stack = thread->m_kernel_stack_pointer;
	Context::switch_task_stack(thread->m_kernel_stack_end);
}

void Scheduler::save_context(const ISRContextFrame* current_context, Thread* thread)
{
	thread->m_kernel_stack_pointer = current_context->context_stack;
}

void Scheduler::switch_page_directory(uintptr_t page_directory)
{
	Memory::switch_page_directory(page_directory);
}

void Scheduler::schedule_handler(ISRContextFrame* frame)
{
	schedule(frame, ScheduleType::FORCED);
}
<file_sep>/kernel/Tasking/Semaphore.cpp
#include "Semaphore.h"
#include "Lib/Stdlib.h"

Semaphore::Semaphore(size_t t_max_count, size_t t_initial_value) :
    m_spinlock{},
    m_max_count{t_max_count},
    m_count{t_initial_value}
{
	m_spinlock.init();
}

Semaphore::~Semaphore()
{
}

void Semaphore::acquire()
{
	m_spinlock.acquire();

	if (m_count < m_max_count) {
		m_count++;
		m_spinlock.release();
	} else {
		m_spinlock.release();
		Thread::current->wait_on(m_queue);
		acquire();
	}
}

void Semaphore::release()
{
	if (!m_count)
		return;
	m_spinlock.acquire();
	m_queue.wake_up();
	m_count--;
	m_spinlock.release();
}
<file_sep>/kernel/VirtualMemory/Physical.h
#pragma once

#include "Arch/x86/Paging.h"
#include "Arch/x86/Panic.h"
#include "Kernel_map.h"
#include "Lib/Stdlib.h"
#include "Utils/Assert.h"
#include "Utils/Types.h"

#define MAX_PHYSICAL_4K_PAGES (1024 * 1024)
#define TEST_BIT(value, bit)  (((value) >> (bit)) & 1)

class PhysicalMemory
{
  private:
	static uintptr_t find_pages(uintptr_t start_page, size_t count);
	static volatile uint8_t physical_memory_tracer[];
	static volatile unsigned physical_memory_size;

  public:
	static void initialize();
	static bool check_free_pages(uintptr_t page_number, unsigned count);
	static uintptr_t alloc_page(uintptr_t start);
	static uintptr_t alloc_contagious_pages(uintptr_t start, size_t count);
	static void free_pages(uintptr_t page_number, unsigned count);
	static void set_free_pages(uintptr_t page_number, unsigned count);
	static void set_used_pages(uintptr_t page_number, unsigned count);
	static unsigned get_physical_memory_size();
};
<file_sep>/kernel/Arch/x86/Idt.h
#pragma once

#include "Gdt.h"
#include "Isr.h"
#include "Kernel_map.h"
#include "Paging.h"
#include "Utils/Types.h"

#define NUMBER_OF_IDT_ENTRIES    256
#define NUMBER_OF_IDT_EXCEPTIONS 32

enum IDT_ENTRY_FLAGS {
	PRESENT = 0x80,
	RING3 = 0x60,
	RING0 = 0x00,
	TRAP_GATE = 0x7,
	INT_GATE = 0x6,
	TASK_GATE = 0x5,
	GATE_32 = 0x8,
	GATE_16 = 0
};

#pragma pack(1)
struct IDT_DISCRIPTOR {
	uint16_t limit;
	uint32_t base;
};
struct IDTEntry {
	uint16_t offset0_15;
	uint16_t segment;
	uint8_t zero;
	uint8_t type;
	uint16_t offset16_31;
};
#pragma pack()

class IDT
{
  private:
	static void fill_idt(uint32_t base, uint16_t limit);
	static void load_idt();
	static void fill_idt_entry(uint8_t idt_entry, uint32_t address, uint16_t segment, uint8_t type);
	static volatile IDT_DISCRIPTOR idt;
	static volatile IDTEntry idt_entries[];

  public:
	static void setup();
};
<file_sep>/kernel/Tasking/Thread.cpp
#include "Thread.h"
#include "Arch/x86/Context.h"
#include "Devices/Timer/Pit.h"
#include "ScopedLock.h"
#include "Utils/Assert.h"
#include "VirtualMemory/Memory.h"
#include "WaitQueue.h"

IntrusiveList<Thread>* Thread::ready_threads = nullptr;
IntrusiveList<Thread>* Thread::sleeping_threads = nullptr;
Thread* Thread::current = nullptr;
Bitmap* Thread::m_tid_bitmap;
StaticSpinlock Thread::global_lock;

void Thread::setup()
{
	global_lock.init();
	m_tid_bitmap = new Bitmap(MAX_BITMAP_SIZE);
	ready_threads = new IntrusiveList<Thread>;
	sleeping_threads = new IntrusiveList<Thread>;
}

Thread& Thread::create_thread(Process& parent_process, thread_function address, uintptr_t argument)
{
	ScopedLock local_lock(global_lock);
	Thread& new_thread = *new Thread(parent_process, address, argument);
	ready_threads->push_back(new_thread);
	return new_thread;
}

Thread::Thread(Process& parent_process, thread_function address, uintptr_t argument) :
    m_lock{},
    m_tid{reserve_tid()},
    m_parent{parent_process}
{
	m_lock.init();
	void* thread_kernel_stack = Memory::alloc(STACK_SIZE, MEMORY_TYPE::WRITABLE | MEMORY_TYPE::KERNEL);

	uintptr_t stack_pointer = Context::setup_task_stack_context(thread_kernel_stack, STACK_SIZE, uintptr_t(address), //
	                                                            uintptr_t(idle), argument);
	m_kernel_stack_start = uintptr_t(thread_kernel_stack);
	m_kernel_stack_end = m_kernel_stack_start + STACK_SIZE;
	m_kernel_stack_pointer = stack_pointer;
	m_state = ThreadState::RUNNABLE;
}

Thread::~Thread()
{
}

void Thread::wake_up_from_queue()
{
	ScopedLock local_lock(m_lock);
	ready_threads->push_back(*this);
	m_state = ThreadState::RUNNABLE;
}

void Thread::wake_up_from_sleep()
{
	ScopedLock local_lock(m_lock);
	sleeping_threads->remove(*this);
	ready_threads->push_back(*this);
	m_state = ThreadState::RUNNABLE;
}

void Thread::wait_on(WaitQueue& queue)
{
	{
		ScopedLock local_lock(m_lock);
		ready_threads->remove(*this);
		queue.enqueue(*this);
		m_state = ThreadState::BLOCKED_QUEUE;
	}
	yield();
}

void Thread::yield()
{
	asm volatile("int 0x81");
}

void Thread::idle(_UNUSED_PARAM(uintptr_t))
{
	while (1) {
		HLT();
	}
}

unsigned Thread::reserve_tid()
{
	unsigned id = m_tid_bitmap->find_first_unused();
	m_tid_bitmap->set_used(id);
	return id;
}

void Thread::terminate()
{
	ScopedLock local_lock(m_lock);
	ASSERT(m_state == ThreadState::RUNNABLE);
	ready_threads->remove(*this);
	this->~Thread();
}

void Thread::sleep(unsigned ms)
{
	{
		ScopedLock local_lock(current->m_lock);
		current->m_sleep_ticks = PIT::ticks + ms;
		current->m_state = ThreadState::BLOCKED_SLEEP;
		ready_threads->remove(*current);
		sleeping_threads->push_back(*current);
	}
	yield();
}

unsigned Thread::tid()
{
	return m_tid;
}

Process& Thread::parent_process()
{
	return m_parent;
}

ThreadState Thread::state()
{
	return m_state;
}

size_t Thread::number_of_ready_threads()
{
	return ready_threads->size();
}<file_sep>/kernel/Filesystem/FSNode.h
#pragma once

#include "Utils/ErrorCodes.h"
#include "Utils/Result.h"
#include "Utils/String.h"
#include "Utils/StringView.h"
#include "Utils/Types.h"

#define MAX_FILE_NAME 64
enum class OpenFlags { CreateNew, OpenExisting };
enum class OpenMode { Read, Write, ReadWrite };
enum class NodeType { Root, Folder, File, Pipe, Link, Device };

class VirtualFileSystem;

class FSNode
{
  public:
	String m_name;
	int m_permission;
	int m_owner;
	NodeType m_type;
	size_t m_size;

	FSNode(const StringView& name, int permission, int owner, NodeType type, size_t size) :
	    m_name{name},
	    m_permission{permission},
	    m_owner{owner},
	    m_type{type},
	    m_size{size}
	{
	}

	virtual ~FSNode()
	{
	}

	virtual Result<void> open(OpenMode mode, OpenFlags flags)
	{
		UNUSED(mode);
		UNUSED(flags);

		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<void> close()
	{
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<void> read(void* buff, size_t offset, size_t size)
	{
		UNUSED(buff);
		UNUSED(offset);
		UNUSED(size);
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<void> write(const void* buff, size_t offset, size_t size)
	{
		UNUSED(buff);
		UNUSED(offset);
		UNUSED(size);
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<bool> can_read()
	{
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<bool> can_write()
	{
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<void> remove()
	{
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<FSNode&> create(const StringView& name, OpenMode mode, OpenFlags flags)
	{
		UNUSED(name);
		UNUSED(mode);
		UNUSED(flags);
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<void> mkdir(const StringView& name, int flags, int access)
	{
		UNUSED(name);
		UNUSED(flags);
		UNUSED(access);
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<void> link(FSNode& node)
	{
		UNUSED(node);
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<void> unlink(FSNode& node)
	{
		UNUSED(node);
		return ResultError(ERROR_INVALID_OPERATION);
	}

	virtual Result<FSNode&> dir_lookup(const StringView& file_name)
	{
		UNUSED(file_name);
		return ResultError(ERROR_INVALID_OPERATION);
	}

	friend class VFS;
};
<file_sep>/kernel/Utils/Stl.h
#pragma once

template <typename T> struct RemoveReference {
	typedef T Type;
};
template <class T> struct RemoveReference<T&> {
	typedef T Type;
};
template <class T> struct RemoveReference<T&&> {
	typedef T Type;
};

template <typename T> constexpr T&& move(T& t)
{
	return static_cast<T&&>(t);
}

template <class T> constexpr T&& forward(typename RemoveReference<T>::Type& param)
{
	return static_cast<T&&>(param);
}
<file_sep>/kernel/Arch/x86/Isr.cpp

#include "Isr.h"

static isr_function interrupt_dispatcher_vector[NUMBER_OF_IDT_ENTRIES] __attribute__((aligned(4)));

extern "C" uintptr_t isr_vector[];

void ISR::initiate_isr_dispatcher_vector()
{
	for (size_t i = 0; i < NUMBER_OF_IDT_ENTRIES; i++) {
		interrupt_dispatcher_vector[i] = 0;
	}
}

void ISR::register_isr_handler(isr_function address, uint8_t irq_number)
{
	interrupt_dispatcher_vector[irq_number] = (isr_function)address;
}

extern "C" void __attribute__((cdecl)) interrupt_dispatcher(ISRContextFrame info)
{
	if (interrupt_dispatcher_vector[info.irq_number]) {
		interrupt_dispatcher_vector[info.irq_number](&info);
	} else {
		ISR::default_interrupt_handler(&info);
	}
}

void ISR::default_interrupt_handler(ISRContextFrame* info)
{
	if (info->irq_number < 19) {
		// printf("Exception: ");
		// printf(exception_messages[info->irq_number]);
		// printf("\nContext Dump:\n");
		// printf("EIP=%X\t CS=%X\t ESP=%X\t\n", info->eip, info->cs, info->context_stack);
	} else if (info->irq_number < NUMBER_OF_IDT_EXCEPTIONS) {
		// printf("Reserved Exception Number\n");
	} else {
		// printf("Undefined IRQ Number (IRQ %d)\n", info->irq_number);
	}
	HLT();
}

const char* ISR::exception_messages[19] = {"Division by zero",
                                           "Debug",
                                           "Non-maskable interrupt",
                                           "Breakpoint",
                                           "Detected overflow",
                                           "Out-of-bounds",
                                           "Invalid opcode",
                                           "No coprocessor",
                                           "Double fault",
                                           "Coprocessor segment overrun",
                                           "Bad TSS",
                                           "Segment not present",
                                           "Stack fault",
                                           "General protection fault",
                                           "Page fault",
                                           "Unknown interrupt",
                                           "Coprocessor fault",
                                           "Alignment check",
                                           "Machine check"};<file_sep>/kernel/Filesystem/Ustar/TarFS.h
#pragma once

#include "INode.h"
#include "Lib/Stdlib.h"
#include "Utils/Assert.h"
#include "Utils/ErrorCodes.h"
#include "Utils/PathParser.h"
#include "Utils/Result.h"
#include "Utils/Types.h"
#include "Utils/UniquePointer.h"

#define MAX_TAR_FILE_NAME  100
#define TAR_ALIGNMENT      512
#define TAR_OCTAL_SIZE_LEN 12
enum USTARFileType {
	NORMAL = '0',
	HARD_LINK = '1',
	SYMBOLIC_LINK = '2',
	CHARACTER_DEVICE = '3',
	BLOCK_DEVICE = '4',
	DIRECTORY = '5',
	NAMED_PIPE = '6'
};

struct TarHeader {                 /* byte offset */
	char name[MAX_TAR_FILE_NAME];  /*   0 */
	char mode[8];                  /* 100 */
	char uid[8];                   /* 108 */
	char gid[8];                   /* 116 */
	char size[TAR_OCTAL_SIZE_LEN]; /* 124 */
	char mtime[12];                /* 136 */
	char chksum[8];                /* 148 */
	char typeflag;                 /* 156 */
	char linkname[100];            /* 157 */
	char magic[6];                 /* 257 */
	char version[2];               /* 263 */
	char uname[32];                /* 265 */
	char gname[32];                /* 297 */
	char devmajor[8];              /* 329 */
	char devminor[8];              /* 337 */
	char prefix[167];              /* 345 */
	                               /* 500 */
};

class TarFS : public INode
{
  public:
	static UniquePointer<FSNode> alloc(const StringView& name, void* tar_address, size_t size);

	Result<FSNode&> dir_lookup(const StringView& file_name) override;
	~TarFS() override;

  private:
	TarHeader* m_tar_address;

	explicit TarFS(const StringView& name, void* tar_address, size_t size);
	INode& add_child_node(INode& parent, const StringView& name, char type, const size_t size, char* data);
	String regulate_path(const char* path);
	size_t octal_to_decimal(const char* octal);
	inline uintptr_t align_to(uintptr_t address, unsigned alignment);
	void parse_ustar(size_t size);
};<file_sep>/kernel/Filesystem/VirtualFilesystem.cpp
#include "VirtualFilesystem.h"
#include "Arch/x86/Panic.h"
#include "Tasking/ScopedLock.h"
#include "Tasking/Thread.h"
#include "Utils/Assert.h"
#include "Utils/ErrorCodes.h"

List<UniquePointer<FSNode>>* VFS::fs_roots;
Spinlock VFS::lock;

void VFS::setup()
{
	// lock the VFS and nodes.
	fs_roots = new List<UniquePointer<FSNode>>;
	lock.init();
}

Result<UniquePointer<FileDescription>> VFS::open(const StringView& path, OpenMode mode, OpenFlags flags)
{
	auto node = open_node(path, mode, flags);
	if (node.error()) {
		return ResultError(node.error());
	}

	auto open_ret = node.value().open(mode, flags);
	if (open_ret.is_error()) {
		return ResultError(open_ret.error());
	}

	return UniquePointer<FileDescription>::make_unique(node.value());
}

Result<void> VFS::mount(UniquePointer<FSNode>&& new_fs_root)
{
	if (fs_roots->contains([&](UniquePointer<FSNode>& node) {
		    if (node->m_name == new_fs_root->m_name)
			    return true;
		    return false;
	    })) {
		return ResultError(ERROR_FS_ALREADY_EXISTS);
	}
	fs_roots->push_back(move(new_fs_root));
	return ResultError(ERROR_SUCCESS);
}

Result<void> VFS::unmount()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}

Result<void> VFS::remove()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}

Result<void> VFS::make_directory()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}

Result<void> VFS::remove_directory()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}

Result<void> VFS::rename()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}

Result<void> VFS::chown()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}

Result<void> VFS::make_link()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}

Result<void> VFS::remove_link()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}

Result<FSNode&> VFS::traverse_parent_node(const StringView& path)
{
	PathParser parser(path);
	size_t path_element_count = parser.count();
	if (path_element_count == 0) {
		return ResultError(ERROR_FILE_DOES_NOT_EXIST);
	}
	return traverse_node_deep(parser, path_element_count - 1);
}

Result<FSNode&> VFS::traverse_node(const StringView& path)
{
	PathParser parser(path);
	size_t path_element_count = parser.count();
	if (path_element_count == 0)
		ResultError(ERROR_FILE_DOES_NOT_EXIST);

	return traverse_node_deep(parser, path_element_count);
}

Result<FSNode&> VFS::traverse_node_deep(PathParser& parser, size_t depth)
{
	if (fs_roots->size() == 0)
		return ResultError(ERROR_NO_ROOT_NODE);

	FSNode* current = get_root_node(parser.element(0));
	if (!current)
		return ResultError(ERROR_FILE_DOES_NOT_EXIST);

	for (size_t i = 1; i < depth; i++) {
		auto next_node = current->dir_lookup(parser.element(i));
		if (next_node.is_error())
			return ResultError(next_node.error());
		current = &next_node.value();
	}
	return *current;
}

Result<FSNode&> VFS::open_node(const StringView& path, OpenMode mode, OpenFlags flags)
{
	auto node = traverse_node(path);
	FSNode* open_node = nullptr;

	if ((node.error() != ERROR_FILE_DOES_NOT_EXIST) && (flags == OpenFlags::CreateNew)) {
		return ResultError(ERROR_FILE_ALREADY_EXISTS);
	} else if ((node.error() == ERROR_FILE_DOES_NOT_EXIST) && (flags == OpenFlags::CreateNew)) {
		// FIXME: we already went though parent! any optimization ?
		auto parent_node = traverse_parent_node(path);
		ASSERT(!parent_node.is_error());
		PathParser parser(path);
		auto new_node = parent_node.value().create(parser.element(parser.count() - 1), mode, flags);
		if (new_node.is_error()) {
			return ResultError(new_node.error());
		}
		open_node = &new_node.value();
	} else if (node.is_error()) {
		return ResultError(node.error());
	} else {
		open_node = &node.value();
	}
	if (open_node->m_type == NodeType::Folder) {
		return ResultError(ERROR_INVALID_OPERATION);
	}
	return *open_node;
}

FSNode* VFS::get_root_node(const StringView& root_name)
{
	for (auto&& i : *fs_roots) {
		if (i->m_name == root_name) {
			return i.ptr();
		}
	}
	return nullptr;
}<file_sep>/test/CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
#set(CMAKE_CXX_STANDARD 17)
include_directories("../kernel")
enable_testing()

add_compile_definitions("__UNIT_TESTS")
SET(This "tests")
file(GLOB_RECURSE SOURCES_TESTS "*.cpp")
file(GLOB SOURCES   "../kernel/Utils/String.cpp"
                    "../kernel/Utils/StringView.cpp"
                    "../kernel/Utils/Bitmap.cpp"
                    "../kernel/Utils/PathParser.cpp")
add_executable(${This} ${SOURCES} ${SOURCES_TESTS})
target_link_libraries(${This} PUBLIC gtest_main)
add_test(
    NAME ${This}
    COMMAND ${This}
)<file_sep>/kernel/Utils/String.h
#pragma once
#include "Types.h"

class StringView;
class String
{
  private:
	size_t m_size = 0;
	char* m_data = nullptr;
	void cleanup();

  public:
	String(const StringView& str);
	String(const char* str);
	String(const char* str, size_t len);
	String(String&& other);
	String(const String& other);
	String& operator=(String&& other);
	String& operator=(const String& other);
	String& operator=(const char* other);
	~String();

	String& operator+=(const String& other);
	String& operator+=(const char* other);
	String& operator+=(char other);
	String operator+(const String& other) const;
	char operator[](size_t off) const;

	String& push_back(char c);
	String& pop_back();
	String& insert(size_t pos, const String& str);
	String& insert(size_t pos, const String& str, size_t subpos, size_t sublen);
	String& insert(size_t pos, const char* str);
	String& insert(size_t pos, const char* str, size_t subpos, size_t sublen);

	bool operator==(const StringView& other) const;
	bool operator==(const String& other) const;
	bool operator==(const char* other) const;
	bool operator!=(const StringView& other) const;
	bool operator!=(const String& other) const;
	bool operator!=(const char* other) const;
	String substr(size_t pos, size_t len) const;
	size_t find(const String& str, size_t pos = 0) const;
	size_t find(const char* s, size_t pos = 0) const;
	size_t find(char c, size_t pos = 0) const;
	size_t rfind(const String& str, size_t pos = END) const;
	size_t rfind(const char* s, size_t pos = END) const;
	size_t rfind(char c, size_t pos = END) const;
	const char* c_str() const;
	size_t length() const;

	static const size_t END;
	static const size_t NOT_FOUND;

	friend class StringView;
};<file_sep>/kernel/Utils/Algorithm.h
#pragma once

/*
TODO: algorithm functions:
- min max
- align
- swap copy copy_backward move move_backward
- for_each
- sort
- equal_range
- for_adject_pairs for_all_pairs
- copy_if copy_while
- find split
- all_of any_of none_of
- make_heap push_heap pop_heap sort_heap is_heap
- rotate reverse is_sorted
- count accumulate
- equal is_permutation
- uninitialized_fill uninitialized_copy uninitialized_mode
 */
<file_sep>/kernel/Utils/Bitmap.cpp
#include "Bitmap.h"

#ifdef __UNIT_TESTS
	#include <assert.h>
	#include <stdio.h>
	#include <string.h>
	#define ASSERT(x) assert(x)
#else
	#include "Lib/Stdlib.h"
	#include "Utils/Assert.h"
#endif
Bitmap::Bitmap(size_t size) : m_size(size)
{
	ASSERT(size <= MAX_BITMAP_SIZE);
	m_bitmap_data = new uint8_t[size / 8];
	memset(m_bitmap_data, 0, sizeof(size / 8));
}

Bitmap::~Bitmap()
{
	delete m_bitmap_data;
}

void Bitmap::set_used(unsigned position)
{
	set_used(position, 1);
}

void Bitmap::set_used(unsigned position, unsigned count)
{
	if (position > m_size) {
		return;
	}

	uint32_t current_position = position;
	for (size_t i = 0; i < count; i++) {
		m_bitmap_data[current_position / 8] |= (1 << (current_position % 8));
		current_position++;
	}
}

void Bitmap::set_unused(unsigned position)
{
	set_unused(position, 1);
}

void Bitmap::set_unused(unsigned position, unsigned count)
{
	if (position > m_size) {
		return;
	}

	uint32_t current_position = position;
	for (size_t i = 0; i < count; i++) {
		m_bitmap_data[current_position / 8] &= ~(1 << (current_position % 8));
		current_position++;
	}
}

unsigned Bitmap::find_first_unused(unsigned count)
{
	size_t remaining_count = count;
	size_t bit_index = 0;
	while (bit_index < m_size) {
		if (m_bitmap_data[bit_index / 8] == 0xFF)
			bit_index += 8;
		if (!CHECK_BIT(m_bitmap_data[bit_index / 8], bit_index % 8))
			remaining_count--;
		else
			remaining_count = count;

		if (!remaining_count)
			return bit_index - count + 1;
		bit_index++;
	}
	return BITMAP_NO_BITS_LEFT;
}
unsigned Bitmap::find_first_used(unsigned count)
{
	size_t remaining_count = count;
	size_t bit_index = 0;
	while (bit_index < m_size) {
		if (m_bitmap_data[bit_index / 8] == 0)
			bit_index += 8;
		if (CHECK_BIT(m_bitmap_data[bit_index / 8], bit_index % 8))
			remaining_count--;
		else
			remaining_count = count;

		if (!remaining_count)
			return bit_index - count + 1;
		bit_index++;
	}
	return BITMAP_NO_BITS_LEFT;
}
unsigned Bitmap::find_first_unused()
{
	return find_first_unused(1);
}
unsigned Bitmap::find_first_used()
{
	return find_first_used(1);
}<file_sep>/kernel/Utils/Result.h
#pragma once
#include "Assert.h"
#include "Stl.h"
class ResultError
{
  public:
	const unsigned m_error;
	explicit ResultError(unsigned error) : m_error(error)
	{
	}

	ResultError(const ResultError& other) : m_error(other.m_error)
	{
	}

	~ResultError()
	{
	}
};

template <typename T> class Result
{
  private:
	const ResultError m_error;
	union {
		T m_storage;
		const char m_storage_empty[sizeof(T)];
	};

  public:
	Result(const ResultError& error) : m_error(error)
	{
	}

	Result(const Result& other) : m_error(other.m_error), m_storage(other.m_storage)
	{
	}

	Result(Result&& other) : m_error(other.m_error), m_storage(move(other.m_storage))
	{
	}

	Result(const T& result) : m_error(ResultError(0)), m_storage(result)
	{
	}

	Result(T&& result) : m_error(ResultError(0)), m_storage(move(result))
	{
	}

	bool is_error() const
	{
		return m_error.m_error != 0;
	}

	unsigned error() const
	{
		return m_error.m_error;
	}

	T& value()
	{
		ASSERT(!is_error());
		return m_storage;
	}

	~Result()
	{
	}
};

template <typename T> class Result<T&>
{
  private:
	const ResultError m_error;
	T* const m_storage;

  public:
	Result(const ResultError& error) : m_error(error), m_storage(nullptr)
	{
	}

	Result(const Result& other) : m_error(other.m_error), m_storage(other.m_storage)
	{
	}

	Result(T& result) : m_error(ResultError(0)), m_storage(&result)
	{
	}

	Result(T&& result) = delete;

	bool is_error() const
	{
		return m_error.m_error != 0;
	}

	unsigned error() const
	{
		return m_error.m_error;
	}

	T& value()
	{
		ASSERT(!is_error());
		return *m_storage;
	}

	~Result()
	{
	}
};

template <> class Result<void>
{
  private:
	const ResultError m_error;

  public:
	Result(const ResultError& error) : m_error(error)
	{
	}

	Result(const Result& other) : m_error(other.m_error)
	{
	}

	bool is_error() const
	{
		return m_error.m_error != 0;
	}

	unsigned error() const
	{
		return m_error.m_error;
	}

	~Result()
	{
	}
};<file_sep>/kernel/Arch/x86/Idt.cpp
#include "Idt.h"

volatile IDT_DISCRIPTOR IDT::idt __attribute__((aligned(4)));
volatile IDTEntry IDT::idt_entries[NUMBER_OF_IDT_ENTRIES] __attribute__((aligned(PAGE_SIZE)));

void IDT::setup()
{
	ISR::initiate_isr_dispatcher_vector();
	fill_idt((uint32_t)idt_entries, sizeof(IDTEntry) * NUMBER_OF_IDT_ENTRIES);

	for (size_t i = 0; i < NUMBER_OF_IDT_ENTRIES; i++)
		fill_idt_entry(i, (uint32_t)isr_vector[i], KCS_SELECTOR,
		               IDT_ENTRY_FLAGS::PRESENT | IDT_ENTRY_FLAGS::GATE_32 | IDT_ENTRY_FLAGS::INT_GATE |
		                   IDT_ENTRY_FLAGS::RING3);
	load_idt();
}

void IDT::fill_idt(uint32_t base, uint16_t limit)
{
	idt.base = base;
	idt.limit = limit;
}

void IDT::fill_idt_entry(uint8_t idt_entry, uint32_t address, uint16_t segment, uint8_t type)
{
	idt_entries[idt_entry].offset0_15 = ((uint32_t)address & 0xFFFF);
	idt_entries[idt_entry].offset16_31 = ((uint32_t)address & 0xFFFF0000) >> 16;
	idt_entries[idt_entry].segment = segment;
	idt_entries[idt_entry].type = type;
	idt_entries[idt_entry].zero = 0;
}

void IDT::load_idt()
{
	asm volatile("LIDT [%0]" : : "r"(&idt));
}
<file_sep>/kernel/Kernel_map.h
#include "Utils/Types.h"

#define KERNEL_SPACE_SIZE       0x40000000
#define KERNEL_BASE             0xC0000000
#define KERNEL_PHYSICAL_ADDRESS 0x00100000
#define KERNEL_VIRTUAL_ADDRESS  (KERNEL_BASE + KERNEL_PHYSICAL_ADDRESS)
#define VIR_TO_PHY(x)           (x - KERNEL_BASE)

extern uintptr_t KERNEL_START;
extern uintptr_t KERNEL_END;<file_sep>/kernel/Tasking/Process.h
#pragma once

#include "Arch/x86/Spinlock.h"
#include "Filesystem/FileDescriptor.h"
#include "Utils/Bitmap.h"
#include "Utils/List.h"
#include "Utils/Result.h"
#include "Utils/String.h"
#include "Utils/StringView.h"
#include "Utils/Types.h"
#include "Utils/UniquePointer.h"

enum class ProcessState {
	RUNNING,
	ACTIVE,
	BLOCKED,
	SUSPENDED,
};

class Process
{
  private:
	static Bitmap* pid_bitmap;
	static List<Process>* processes;
	static StaticSpinlock global_lock;
	static void initiate_process(uintptr_t pcb);

	Spinlock m_lock;

	Process(const StringView& name, const StringView& path);
	unsigned reserve_pid();
	Result<uintptr_t> load_executable(const StringView& path);

  public:
	static Process& create_new_process(const StringView& name, const StringView& path);
	static void setup();

	const unsigned m_pid;
	const String m_name;
	const String m_path;
	const uintptr_t m_page_directory;
	const ProcessState m_state;
	const Process* m_parent;
	Descriptor<FileDescription> m_file_descriptors;
	~Process();

	friend class List<Process>;
};
<file_sep>/kernel/Tasking/SystemCall.cpp
#include "SystemCall.h"
#include "Arch/x86/Isr.h"
#include "Filesystem/VirtualFilesystem.h"
#include "Tasking/Process.h"
#include "Tasking/Thread.h"
#include "Utils/Stl.h"

#pragma GCC diagnostic ignored "-Wcast-function-type"

void SystemCall::setup()
{
	ISR::register_isr_handler(systemcall_handler, SYSCALL_IRQ);
}

generic_syscall SystemCall::get_syscall_routine(unsigned syscall_num)
{
	if (syscall_num < syscalls_count) {
		return systemcalls_routines[syscall_num];
	}
	return nullptr;
}

void SystemCall::systemcall_handler(ISRContextFrame* frame)
{

	dbg() << "System Call " << Context::syscall_num(frame) << " (" << Hex(Context::syscall_param1(frame)) << " ,"
	      << Hex(Context::syscall_param2(frame)) << " ," << Hex(Context::syscall_param3(frame)) << " ,"
	      << Hex(Context::syscall_param4(frame)) << " ," << Hex(Context::syscall_param5(frame)) << ")";

	generic_syscall syscall = get_syscall_routine(Context::syscall_num(frame));
	if (!syscall) {
		PANIC("undefined systemcall invoked");
	}
	auto ret = syscall(Context::syscall_param1(frame), Context::syscall_param2(frame), Context::syscall_param3(frame),
	                   Context::syscall_param4(frame), Context::syscall_param5(frame));

	Context::set_return_value(frame, ret.error());
	if (ret.is_error()) {
		Context::set_return_arg1(frame, 0);
	} else {
		Context::set_return_arg1(frame, ret.value());
	}
}

generic_syscall SystemCall::systemcalls_routines[] = {reinterpret_cast<generic_syscall>(OpenFile),
                                                      reinterpret_cast<generic_syscall>(ReadFile),
                                                      reinterpret_cast<generic_syscall>(WriteFile),
                                                      reinterpret_cast<generic_syscall>(CloseFile),

                                                      reinterpret_cast<generic_syscall>(CreateThread),
                                                      reinterpret_cast<generic_syscall>(CreateRemoteThread), //
                                                      reinterpret_cast<generic_syscall>(CreateProcess),
                                                      reinterpret_cast<generic_syscall>(Sleep),
                                                      reinterpret_cast<generic_syscall>(Yield)};

unsigned SystemCall::syscalls_count = sizeof(systemcalls_routines) / sizeof(generic_syscall);

Result<int> OpenFile(char* path, int mode, int flags)
{
	auto file_description = VFS::open(path, static_cast<OpenMode>(mode), static_cast<OpenFlags>(flags));
	if (file_description.is_error()) {
		return ResultError(file_description.error());
	}

	unsigned fd = Thread::current->parent_process().m_file_descriptors.add_descriptor(move(file_description.value()));
	return fd;
}

Result<int> ReadFile(unsigned descriptor, void* buff, size_t size)
{
	// FIXME: check if descriptor exists.
	auto& description = Thread::current->parent_process().m_file_descriptors.get_description(descriptor);
	auto result = description.read(buff, size);
	if (result.is_error()) {
		return ResultError(result.error());
	}
	return 0;
}

Result<int> WriteFile(unsigned descriptor, void* buff, size_t size)
{
	// FIXME: check if descriptor exists.
	auto& description = Thread::current->parent_process().m_file_descriptors.get_description(descriptor);
	auto result = description.read(buff, size);
	if (result.is_error()) {
		return ResultError(result.error());
	}
	return 0;
}

Result<int> CloseFile(unsigned descriptor)
{
	// FIXME: check if descriptor exists.
	auto& description = Thread::current->parent_process().m_file_descriptors.get_description(descriptor);
	Thread::current->parent_process().m_file_descriptors.remove_descriptor(descriptor);
	return 0;
}

Result<int> CreateThread(void* address, int arg)
{
	return 0;
}

Result<int> CreateRemoteThread(int process, void* address, int arg)
{
	return 0;
}

Result<int> CreateProcess(char* name, char* path, int flags)
{
	UNUSED(flags);
	Process::create_new_process(name, path);
	return 0;
}

Result<int> Sleep(size_t size)
{
	Thread::sleep(size);
	return 0;
}

Result<int> Yield()
{
	Thread::yield();
	return 0;
}
<file_sep>/kernel/Devices/DeviceFS.cpp
#include "DeviceFS.h"
#include "Tasking/ScopedLock.h"
#include "Utils/ErrorCodes.h"
#include "Utils/Stl.h"

List<UniquePointer<FSNode>>* DeviceFS::children = nullptr;

UniquePointer<FSNode> DeviceFS::alloc(const StringView& name)
{
	return UniquePointer<FSNode>(new DeviceFS(name));
}

DeviceFS::DeviceFS(const StringView& name) : FSNode{name, 0, 0, NodeType::Root, 0}
{
	ASSERT(children == 0);
	children = new List<UniquePointer<FSNode>>;
}

DeviceFS::~DeviceFS()
{
}

Result<FSNode&> DeviceFS::dir_lookup(const StringView& file_name)
{
	for (auto& i : *children) {
		if (i->m_name == file_name) {
			return *i;
		}
	}
	return ResultError(ERROR_DEVICE_DOESNOT_EXIST);
}

Result<void> DeviceFS::add_device(UniquePointer<FSNode>&& new_device)
{
	if (children->contains([&](UniquePointer<FSNode>& device) {
		    if (device->m_name == new_device->m_name)
			    return true;
		    return false;
	    })) {
		return ResultError(ERROR_DEVICE_ALREADY_EXISTS);
	}

	children->push_back(move(new_device));
	return ResultError(ERROR_SUCCESS);
}

Result<void> DeviceFS::remove_device(const StringView& name)
{
	UNUSED(name);
	return ResultError(ERROR_INVALID_OPERATION);
}<file_sep>/kernel/Arch/x86/Paging.h
#pragma once

#include "Kernel_map.h"
#include "Lib/Stdlib.h"
#include "Utils/Types.h"

#define NUMBER_OF_PAGE_DIRECOTRY_ENTRIES 1024
#define NUMBER_OF_PAGE_TABLE_ENTRIES     1024
#define FULL_KERNEL_PAGES                (NUMBER_OF_PAGE_DIRECOTRY_ENTRIES - GET_NUMBER_OF_DIRECTORIES(KERNEL_BASE))
#define RECURSIVE_ENTRY                  (NUMBER_OF_PAGE_DIRECOTRY_ENTRIES - 1)

#define CR4_PSE    (1 << 4)
#define CR0_PAGING (1 << 31)
#define CR0_WP     (1 << 16)

#define GET_FRAME(x)                                    (x >> 12)
#define GET_PTE_INDEX(x)                                ((x >> 12) & 0x3FF)
#define GET_PDE_INDEX(x)                                (x >> 22)
#define GET_NUMBER_OF_DIRECTORIES(x)                    (x >> 22)
#define GET_OFFSET(x)                                   (x & 0xFFF)
#define GET_PAGE_VIRTUAL_ADDRESS(dir_index, page_index) (((dir_index) << 22) | ((page_index) << 12))
#define BOOL(x)                                         ((bool)(x))

#define GET_PAGES(x)  (x / PAGE_SIZE + ((x % PAGE_SIZE) == 0 ? 0 : 1))
#define PAGE_ALIGN(x) (GET_PAGES(x) * PAGE_SIZE)

#define PAGE_SIZE          0x1000
#define FIRST_PAGE_ADDRESS 0x1000
#define LAST_PAGE_ADDRESS  GET_PAGE_VIRTUAL_ADDRESS(RECURSIVE_ENTRY - 1, NUMBER_OF_PAGE_TABLE_ENTRIES - 1)

#define PAGE_FLAGS_PRESENT  1
#define PAGE_FLAGS_USER     2
#define PAGE_FLAGS_WRITABLE 4
#define PAGE_FLAGS_GLOBAL   8

typedef volatile struct PAGE_TABLE_ENTRY_t {
	uint32_t present : 1;  // Page present in memory
	uint32_t rw : 1;       // Read-only if clear, readwrite if set
	uint32_t user : 1;     // Supervisor level only if clear
	uint32_t pwt : 1;      // Page-level write-through
	uint32_t pcd : 1;      // Page-level cache disable
	uint32_t accessed : 1; // Has the page been accessed since last refresh?
	uint32_t dirty : 1;    // Has the page been written to since last refresh?
	uint32_t pse : 1;      // 4MB Page
	uint32_t global : 1;   // page is global
	uint32_t unused : 3;   // Amalgamation of unused and reserved bits
	uint32_t frame : 20;   // Frame address (shifted right 12 bits)
} PAGE_TABLE_ENTRY;

typedef PAGE_TABLE_ENTRY PAGE_DIRECTORY_ENTRY;

typedef volatile struct PAGE_DIRECTORY_t {
	PAGE_DIRECTORY_ENTRY entries[NUMBER_OF_PAGE_DIRECOTRY_ENTRIES];
} PAGE_DIRECTORY;

typedef volatile struct PAGE_TABLE_t {
	PAGE_TABLE_ENTRY entries[NUMBER_OF_PAGE_TABLE_ENTRIES];
} PAGE_TABLE;

class Paging
{
  private:
	static void setup_page_tables();
	static void initialize_page_directory(PAGE_DIRECTORY* page_direcotry);
	static void initialize_page_table(PAGE_TABLE* page_direcotry);
	static void fill_directory_entry(PAGE_DIRECTORY_ENTRY* page_direcotry_entry, uint16_t physical_frame,
	                                 uint32_t flags);
	static void fill_directory_PSE_entry(PAGE_DIRECTORY_ENTRY* page_direcotry_entry, uint16_t physical_frame,
	                                     uint32_t flags);
	static void fill_page_table_entry(PAGE_TABLE_ENTRY* page_table_entry, uint16_t physical_frame, uint32_t flags);
	static bool check_page_exits_in_table(uint32_t virtual_address);
	static void invalidate_page(uint32_t addr);
	static void enable_PSE();
	static void enable_paging();
	static PAGE_DIRECTORY page_direcotry;
	static PAGE_TABLE kernel_page_tables[];
	static PAGE_TABLE boostrap_page_table[];

  public:
	static void setup(uint32_t num_kernel_pages);
	static void map_pages(uint32_t virtual_address, uint32_t physical_address, uint32_t pages, uint32_t flags);
	static void map_boot_pages(uint32_t virtual_address, uint32_t physical_address, uint32_t pages);
	static void unmap_pages(uint32_t virtual_address, uint32_t pages);
	static bool check_page_present(uint32_t virtual_address);
	static bool check_page_table_exists(uint32_t virtual_address);
	static uint32_t get_physical_page(uint32_t virtual_address);
	static void load_page_directory(uint32_t page_direcotry);
	static void map_kernel_pd_entries(uint32_t pd);
	static void map_page_table(uint32_t virtual_address, uint32_t pt);
	static void map_page(uint32_t virtual_address, uint32_t physical_address, uint32_t flags);
	static void unmap_page(uint32_t virtual_address);
};
<file_sep>/kernel/Utils/Stack.h
#pragma once

#include "Utils/Stl.h"
#include "Utils/Types.h"
#ifdef __UNIT_TESTS
	#include <assert.h>
	#define ASSERT(x) assert(x)
#else
	#include "Assert.h"
#endif
template <typename T> class Stack
{
  private:
	T* m_data;
	size_t m_head;
	size_t m_size;
	const size_t m_capacity;

  public:
	explicit Stack(const size_t capacity);
	void queue(const T&);
	void queue(T&&);
	T dequeue();
	T& back();
	bool is_empty();
	bool is_full();
	size_t capacity();
	size_t size();
	size_t available_size();
	~Stack();
};

template <typename T>
Stack<T>::Stack(const size_t capacity) :
    m_data{new T[capacity]}, //
    m_head{0},
    m_size{0},
    m_capacity{capacity}
{
}

template <typename T> void Stack<T>::queue(const T& data_to_queue)
{
	ASSERT(!is_full());
	m_data[m_head] = data_to_queue;
	m_head++;
	m_size++;
}

template <typename T> void Stack<T>::queue(T&& data_to_queue)
{
	ASSERT(!is_full());
	m_data[m_head] = move(data_to_queue);
	m_head++;
	m_size++;
}

template <typename T> T Stack<T>::dequeue()
{
	ASSERT(!is_empty());
	T ret_data = move(m_data[m_head - 1]);
	m_data[m_head - 1].~T();
	m_head--;
	m_size--;
	return ret_data;
}

template <typename T> T& Stack<T>::back()
{
	return m_data[m_head - 1];
}

template <typename T> Stack<T>::~Stack()
{
	for (size_t i = 0; i < m_head; i++) {
		m_data[i].~T();
	}
	::operator delete(m_data, sizeof(T) * m_capacity);
}

template <typename T> bool Stack<T>::is_empty()
{
	return m_size == 0;
}

template <typename T> bool Stack<T>::is_full()
{
	return m_size == m_capacity;
}

template <typename T> size_t Stack<T>::capacity()
{
	return m_capacity;
}

template <typename T> size_t Stack<T>::size()
{
	return m_size;
}

template <typename T> size_t Stack<T>::available_size()
{
	return capacity() - size();
}<file_sep>/kernel/Tasking/Scheduler.h
#pragma once

#include "Arch/x86/Context.h"
#include "Arch/x86/Spinlock.h"
#include "Process.h"
#include "Thread.h"
#include "Utils/Result.h"
#include "Utils/Types.h"

enum class ScheduleType {
	FORCED,
	TIMED,
};

class Scheduler
{
  private:
	static StaticSpinlock lock;
	static void load_context(ISRContextFrame* current_context, const Thread* thread);
	static void switch_page_directory(const uintptr_t page_directory);
	static void save_context(const ISRContextFrame* current_context, Thread* thread);
	static void wake_up_sleepers();
	static void schedule_handler(ISRContextFrame* frame);
	static Thread& select_next_thread();

  public:
	static void schedule(ISRContextFrame* current_context, ScheduleType type);
	static void setup();
};<file_sep>/kernel/Filesystem/FileDescription.cpp
#include "FileDescription.h"
#include "FSNode.h"
#include "Utils/ErrorCodes.h"

FileDescription::FileDescription(FSNode& node) : m_node(node)
{
}

FileDescription::~FileDescription()
{
	m_node.close();
}

Result<void> FileDescription::read(void* buff, size_t size)
{
	size_t reading_size = m_current_position + size;
	if (reading_size > m_node.m_size) {
		return ResultError(ERROR_EOF);
	}
	return m_node.read(buff, m_current_position, size);
}

Result<void> FileDescription::write(const void* buff, size_t size)
{
	size_t offset = m_current_position + size;
	if (offset > m_node.m_size && m_node.m_size != 0) {
		return ResultError(ERROR_EOF);
	}
	return m_node.write(buff, offset, size);
}

Result<void> FileDescription::seek(int offset, SeekOrigin origin)
{
	switch (origin) {
		case SeekOrigin::SET: {
			if (offset < 0)
				return ResultError(ERROR_EOF);
			if (size_t(offset) > m_node.m_size)
				return ResultError(ERROR_EOF);

			m_current_position = offset;
			break;
		}
		case SeekOrigin::CURRENT: {
			if (((offset > 0) && (size_t(offset) > (m_node.m_size - m_current_position))) ||
			    ((offset < 0) && (size_t(-offset) > m_current_position)))
				return ResultError(ERROR_EOF);

			m_current_position = offset + m_current_position;
			break;
		}
		case SeekOrigin::END: {
			if (offset > 0)
				return ResultError(ERROR_EOF);
			if (size_t(-offset) > m_node.m_size)
				return ResultError(ERROR_EOF);

			m_current_position = m_node.m_size + offset;
			break;
		}
		default:
			break;
	}
	return ResultError(ERROR_SUCCESS);
}

Result<FileInfo> FileDescription::fstat()
{
	return FileInfo{m_node.m_size};
}

Result<void> FileDescription::ioctl()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}

Result<void> FileDescription::mmap()
{
	return ResultError(ERROR_INVALID_PARAMETERS);
}<file_sep>/kernel/VirtualMemory/Virtual.cpp
#include "Virtual.h"

uintptr_t VirtualMemory::find_pages(uint32_t start_address, uint32_t end_address, uint32_t pages_num)
{

	uint32_t remaining_pages = pages_num;
	uint32_t first_free_page = 0;
	uint32_t vAdd = start_address;

	while (vAdd < end_address) {
		if (!Paging::check_page_present(vAdd)) {
			if (remaining_pages == pages_num)
				first_free_page = vAdd;
			if (!(--remaining_pages))
				return uintptr_t(first_free_page);
		} else {
			remaining_pages = pages_num;
		}
		vAdd += PAGE_SIZE;
	}

	PANIC("No virtual memory available!");
	ASSERT_NOT_REACHABLE();
	return uintptr_t(nullptr);
}

bool VirtualMemory::check_free_pages(uint32_t start_address, uint32_t pages_num)
{

	for (size_t i = 0; i < pages_num; i++) {
		if (Paging::check_page_present(start_address + (i * PAGE_SIZE))) {
			return false;
		}
	}
	return true;
}

uintptr_t VirtualMemory::create_page_table()
{
	uintptr_t pt_addr =
	    (uintptr_t)Memory::_alloc_no_lock(sizeof(PAGE_TABLE), MEMORY_TYPE::KERNEL | MEMORY_TYPE::WRITABLE);
	Paging::unmap_pages(pt_addr, GET_PAGES(sizeof(PAGE_TABLE))); // we don't need table to be in virtual memory.
	return pt_addr;
}
void VirtualMemory::map_pages(uintptr_t virtual_address, uintptr_t physical_address, uint32_t pages, uint32_t flags)
{
	for (size_t i = 0; i < pages; i++) {
		if (Paging::check_page_table_exists(virtual_address) == false) {
			Paging::map_page_table(virtual_address, create_page_table());
		}
		Paging::map_page(virtual_address + PAGE_SIZE * i, physical_address + PAGE_SIZE * i, flags);
	}
}<file_sep>/kernel/Arch/x86/Gdt.h
#pragma once

#include "Kernel_map.h"
#include "Lib/Stdlib.h"
#include "Paging.h"
#include "Utils/Types.h"

#define GDT_NUMBER_OF_ENTRIES              6
#define SEGMENT_SELECTOR(index, prv_level) (index << 3 | prv_level)
#define SEGMENT_INDEX(segment)             (segment >> 3)
#define KCS_SELECTOR                       SEGMENT_SELECTOR(1, 0)
#define KDS_SELECTOR                       SEGMENT_SELECTOR(2, 0)
#define UCS_SELECTOR                       SEGMENT_SELECTOR(3, 3)
#define UDS_SELECTOR                       SEGMENT_SELECTOR(4, 3)
#define TSS_SELECTOR                       SEGMENT_SELECTOR(5, 3)

#define SEG_DESCTYPE(x) (((x)&0x01) << 0x04) // Descriptor type (0 for system, 1 for code/data)
#define SEG_PRES(x)     (((x)&0x01) << 0x07) // Present
#define SEG_PRIV(x)     (((x)&0x03) << 0x05) // Set privilege level (0 - 3)

#define SEG_SAVL(x) ((x) << 0x0C) // Available for system use
#define SEG_LONG(x) ((x) << 0x0D) // Long mode
#define SEG_SIZE(x) ((x) << 0x0E) // Size (0 for 16-bit, 1 for 32)
#define SEG_GRAN(x) ((x) << 0x0F) // Granularity (0 for 1B - 1MB, 1 for 4KB - 4GB)

#define SEG_DATA_RD        0x00 // Read-Only
#define SEG_DATA_RDA       0x01 // Read-Only, accessed
#define SEG_DATA_RDWR      0x02 // Read/Write
#define SEG_DATA_RDWRA     0x03 // Read/Write, accessed
#define SEG_DATA_RDEXPD    0x04 // Read-Only, expand-down
#define SEG_DATA_RDEXPDA   0x05 // Read-Only, expand-down, accessed
#define SEG_DATA_RDWREXPD  0x06 // Read/Write, expand-down
#define SEG_DATA_RDWREXPDA 0x07 // Read/Write, expand-down, accessed
#define SEG_CODE_EX        0x08 // Execute-Only
#define SEG_CODE_EXA       0x09 // Execute-Only, accessed
#define SEG_CODE_EXRD      0x0A // Execute/Read
#define SEG_CODE_EXRDA     0x0B // Execute/Read, accessed
#define SEG_CODE_EXC       0x0C // Execute-Only, conforming
#define SEG_CODE_EXCA      0x0D // Execute-Only, conforming, accessed
#define SEG_CODE_EXRDC     0x0E // Execute/Read, conforming
#define SEG_CODE_EXRDCA    0x0F // Execute/Read, conforming, accessed
#define SEG_TSS_AVAILABLE  0x9

#define GDT_CODE_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_PRIV(0) | SEG_CODE_EXRDA
#define GDT_DATA_PL0 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_PRIV(0) | SEG_DATA_RDWR
#define GDT_CODE_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_PRIV(3) | SEG_CODE_EXRDA
#define GDT_DATA_PL3 SEG_DESCTYPE(1) | SEG_PRES(1) | SEG_PRIV(3) | SEG_DATA_RDWR
#define GDT_TSS_PL3  SEG_DESCTYPE(0) | SEG_PRES(1) | SEG_PRIV(3) | SEG_TSS_AVAILABLE

#pragma pack(1)
struct GDT_DESCRIPTOR {
	uint16_t limit;
	uint32_t base;
};
struct GDT_ENTRY {
	uint16_t lim0_15;
	uint16_t base0_15;
	uint8_t base16_23;
	uint8_t access;
	uint8_t lim16_19 : 4;
	uint8_t flags : 4;
	uint8_t base24_31;
};
struct TSS_ENTRY {
	uint32_t prev_tss;
	uint32_t esp0;
	uint32_t ss0;
	uint32_t esp1;
	uint32_t ss1;
	uint32_t esp2;
	uint32_t ss2;
	uint32_t cr3;
	uint32_t eip;
	uint32_t eflags;
	uint32_t eax;
	uint32_t ecx;
	uint32_t edx;
	uint32_t ebx;
	uint32_t esp;
	uint32_t ebp;
	uint32_t esi;
	uint32_t edi;
	uint32_t es;
	uint32_t cs;
	uint32_t ss;
	uint32_t ds;
	uint32_t fs;
	uint32_t gs;
	uint32_t ldt;
	uint16_t trap;
	uint16_t iomap_base;
};
#pragma pack()

class GDT
{
  private:
	static void fill_gdt(uint32_t base, uint16_t limit);
	static void load_segments(uint16_t code_segment, uint16_t data_segment);
	static void load_gdt();
	static void fill_gdt_entry(uint32_t gdt_entry, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags);
	static void load_tss(uint16_t tss);

	static volatile GDT_DESCRIPTOR gdt;
	static volatile GDT_ENTRY gdt_entries[];
	static volatile TSS_ENTRY tss_entry;

  public:
	static void setup();
	static void setup_tss(uint32_t kernel_stack);
	static void set_tss_stack(uint32_t kernel_stack);
};
<file_sep>/CMakeLists.txt
cmake_minimum_required(VERSION 3.0.0)
set(CMAKE_ASM_NASM_OBJECT_FORMAT win32)
enable_language(ASM_NASM)
project(CyanOS VERSION 0.1.0)


SET(OUTPUT_FILE "kernel")
SET(OUTPUT_IMAGE ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILE}.img)
SET(BINS_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/apps)
SET(DRVS_DIRECTORY ${BINS_DIRECTORY}/Drivers)
SET(USER_DIRECTORY ${BINS_DIRECTORY}/UserBinary)
SET(ROOT_DIRECTORY "CyanOS_root")
SET(OUTPUT_ISO "CyanOS.iso")
SET(QEMU qemu-system-i386)
SET(QEMU_FLAGS -serial stdio  -serial file:CON -no-reboot -no-shutdown -m 128 -d cpu_reset -boot d -cdrom)
SET(QEMU_FLAGS_DEBUG -serial stdio  -serial file:CON -S -gdb tcp::5555)
file(MAKE_DIRECTORY ${BINS_DIRECTORY} ${DRVS_DIRECTORY} ${USER_DIRECTORY})

#set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-checks=*")

add_subdirectory("kernel")


add_custom_command(
        OUTPUT  ${OUTPUT_ISO}
        MAIN_DEPENDENCY  ${OUTPUT_FILE}
        COMMAND python ../utils/make_bootable_iso.py ${OUTPUT_IMAGE} ${BINS_DIRECTORY} ${ROOT_DIRECTORY} ${OUTPUT_ISO}
        COMMENT "Creating ISO file..."
)

add_custom_target(compile ALL DEPENDS ${OUTPUT_ISO})

add_custom_target(debug
    DEPENDS ${OUTPUT_ISO}
    COMMAND ${QEMU} ${QEMU_FLAGS} ${OUTPUT_ISO} ${QEMU_FLAGS_DEBUG}
)

add_custom_target(run
    DEPENDS ${OUTPUT_ISO}
    COMMAND ${QEMU} ${QEMU_FLAGS} ${OUTPUT_ISO}
)

enable_testing()
add_subdirectory("googletest")
add_subdirectory("test")
include(CTest)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
<file_sep>/kernel/Arch/x86/Spinlock.cpp
#include "Spinlock.h"

void StaticSpinlock::init()
{
	m_value = 0;
}

void StaticSpinlock::acquire()
{
	m_eflags = eflags_read();
	DISABLE_INTERRUPTS();
	while (test_and_set(&m_value) != 0) {
	}
}

void StaticSpinlock::release()
{
	m_value = 0;
	eflags_write(m_eflags);
}
<file_sep>/kernel/Tasking/Loader/PE.h

#pragma once

#include "Utils/Result.h"
#include "Utils/Types.h"
#include "Winnt.h"

class PELoader
{
  private:
	static uintptr_t align_to(uintptr_t size, size_t alignment);
	static void* load_pe_sections(const char* file, const IMAGE_NT_HEADERS32* nt_header);

  public:
	static Result<uintptr_t> load(const char* file, size_t size);
	PELoader() = delete;
	~PELoader() = delete;
};
<file_sep>/kernel/Kernel_init.cpp
#include "Kernel_init.h"
#include "Arch/x86/Asm.h"
#include "Arch/x86/Gdt.h"
#include "Arch/x86/Idt.h"
#include "Arch/x86/Paging.h"
#include "Arch/x86/Panic.h"
#include "Arch/x86/Pic.h"
#include "Devices/Console/Console.h"
#include "Devices/DebugPort/DebugPort.h"
#include "Devices/DebugPort/Logger.h"
#include "Devices/DeviceFS.h"
#include "Devices/Keyboard/Keyboard.h"
#include "Devices/RTC/Rtc.h"
#include "Devices/Timer/Pit.h"
#include "Filesystem/Pipes/PipeFS.h"
#include "Filesystem/Ustar/TarFS.h"
#include "Tasking/Process.h"
#include "Tasking/Scheduler.h"
#include "Tasking/Semaphore.h"
#include "Tasking/Thread.h"
#include "Tests.h"
#include "Utils/Assert.h"
#include "Utils/Stl.h"
#include "Utils/UniquePointer.h"
#include "VirtualMemory/Heap.h"
#include "VirtualMemory/Memory.h"

void display_time()
{
	while (1) {
		DATE_TIME date;
		RTC::get_time(&date);
		// printf("Time is %d:%d:%d  %d-%d-20%d\n", date.year, date.minutes, date.seconds, date.day_of_month,
		// date.month,
		//      date.year);
		// Scheduler::sleep(500);
		// removeLine();
	}
}

extern "C" void kernel_init(BootloaderInfo* boot_info)
{
	Logger::init();
	Logger(DebugColor::Bright_Cyan) << "Welcome To CyanOS.";

	info() << "Setting up core components... ";
	GDT::setup();
	IDT::setup();
	Memory::setup_stage2();
	Heap::setup();
	Scheduler::setup();
	PIC::setup();
	PIT::setup();
	info() << "\bDone!";

	info() << "Setting up file systems... ";
	VFS::setup();
	VFS::mount(TarFS::alloc("Tar", reinterpret_cast<void*>(boot_info->ramdisk.start), boot_info->ramdisk.size));
	VFS::mount(PipeFS::alloc("Pipes"));
	VFS::mount(DeviceFS::alloc("Devices"));
	info() << "\bDone!";

	info() << "Setting up devices... ";
	DeviceFS::add_device(Keyboard::alloc("keyboard"));
	DeviceFS::add_device(Console::alloc("console"));
	info() << "\bDone!";

	info() << "Starting the first process.";
	Process& proc = Process::create_new_process("test_process", "/Tar/Drivers/open_file.exe");
	Thread::create_thread(proc, test_console, 0);
	Thread::create_thread(proc, test_keyboard, 0);
	Thread::create_thread(proc, test_keyboard2, 0);

	Thread::yield();
	while (1) {
		HLT();
	}
	ASSERT_NOT_REACHABLE();
}<file_sep>/README.md

<p align="center">
  <img width="400" height="80" src="https://i.imgur.com/KVBFGI0.png">
</p>

# CyanOS: A Hobbyist Operating System [![Build Status](https://travis-ci.com/AymenSekhri/CyanOS.svg?branch=master)](https://travis-ci.com/AymenSekhri/CyanOS)

## What's is this ?
It's a x86 monolithic kernel operating system, coded in C++ 17 and few lines of x86 Assembly.

## Why ?
Why a new half working operating systems? you might ask, And the answer: because it's fun. This is my biggest project so far and I'm really learning a lot of new stuff on the way and enjoying every line I write (until I face a race condition bug, I would hate my life by then). I'm trying my best to work out a clean architecture for this project and maintaining a readable & scalable code base as far as i can (it might far from perfect right now).

## What can it do ?
- Virtual Memory.
- Heap Allocator.
- Concurrency in terms of Threads & Processes.
- Basic Windows PE loader
- Task Synchronization (Spinlocks, Semaphores and Mutex)
- Inter-process communication (using pipes)
- Virtual File System.
- User Space.
- PIC Driver.
- Keyboard Driver.

## Building CyanOS
#### Requirements
```
sudo apt-get update
sudo apt-get install build-essential g++-multilib nasm python cmake grub2 xorriso mtools qemu 
```
For Windows users, you can build and run the system on WSL1/WSL2 (Windows Subsystem for Linux). Or you can build it using [msys2](http://repo.msys2.org/distrib/x86_64/), [nasm](https://www.nasm.us/) and [CMake](https://cmake.org/download) and run it using [qemu](https://www.qemu.org/download/), though it still needs WSL to make a bootable ISO using `grub2-rescue` command.

#### Building
```
git clone --recursive https://github.com/AymenSekhri/CyanOS.git
cd ./CyanOS
mkdir build && cd build
cmake ..
make && make test
```
And you can boot up the OS in Qemu using:
```
make run
```

## You have a question or suggestion ?
Add an issue, and I will be happy to answer you.

## Acknowledgement
I would like to thank [<NAME>](https://github.com/awesomekling), I leant so much from his [youtube channel](https://www.youtube.com/c/AndreasKling/) and his great open source project [SerenityOS](https://github.com/SerenityOS/serenity).

## Useful resources
* Operating Systems: Internals And Design Principles By <NAME>.
* Operating Systems: Design and Implementation By <NAME> and <NAME>.
* [Brokenthorn Tutorials](http://www.brokenthorn.com/Resources)
* [littleosbook Tutorials](https://littleosbook.github.io)
* [<NAME> Tutorials](http://www.jamesmolloy.co.uk/tutorial_html)
* [How to Make a Computer Operating System](https://samypesse.gitbook.io/how-to-create-an-operating-system/)
* [OSDev](https://wiki.osdev.org/Main_Page)
* [Intel Manual](https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.pdf)
<file_sep>/kernel/Filesystem/FileDescription.h
#pragma once

#include "FSNode.h"
#include "Utils/Result.h"
#include "Utils/Types.h"

enum class SeekOrigin { SET, CURRENT, END };
struct FileInfo {
	size_t size;
};

class FileDescription
{
  private:
	FSNode& m_node;
	size_t m_current_position = 0;
	int m_type = 0;
	bool m_has_changed = false;

  public:
	FileDescription(FSNode& node);
	~FileDescription();
	Result<void> read(void* buff, size_t size);
	Result<void> write(const void* buff, size_t size);
	Result<void> seek(int offset, SeekOrigin origin);
	Result<FileInfo> fstat();
	Result<void> ioctl();
	Result<void> mmap();
};<file_sep>/kernel/VirtualMemory/Heap.h
#pragma once

#include "Arch/x86/Spinlock.h"
#include "Lib/Stdlib.h"
#include "Memory.h"
#include "Utils/Types.h"

#define ADDR_TO_HEADER(x)                  ((unsigned)x - sizeof(BlockHeader))
#define HEADER_TO_ADDR(x)                  ((unsigned)x + sizeof(BlockHeader))
#define NEXT_NEIGHBOR_BLOCK(current_block) ((unsigned)current_block + sizeof(BlockHeader) + current_block->size)
#define MALLOC_PAGE_SIZE                   PAGE_SIZE
#define MAX_SIZE                           (MALLOC_PAGE_SIZE - sizeof(BlockHeader) * 2 - sizeof(PageFrameBlock))

struct BlockHeader {
	unsigned size;
	BlockHeader *next, *previous;
};
struct PageFrameBlock {
	unsigned size;
	PageFrameBlock *next, *previous;
};
class Heap
{
  private:
	static StaticSpinlock lock;
	static PageFrameBlock* create_new_page();
	static PageFrameBlock* get_last_page();
	static BlockHeader* initiate_first_block(PageFrameBlock* new_page);
	static BlockHeader* find_free_block(unsigned size);
	static void link_block(BlockHeader* current_block, BlockHeader* new_block);
	static void unlink_block(BlockHeader* current_block);
	static volatile PageFrameBlock* malloc_mem;

  public:
	static void setup();
	static void* kmalloc(unsigned size, unsigned flags);
	static void kfree(void* addr);
};
<file_sep>/kernel/Devices/DebugPort/Logger.cpp
#include "Logger.h"
#include "Lib/Stdlib.h"

StaticSpinlock Logger::lock;

void Logger::init()
{
	lock.init();
}

Logger::Logger(DebugColor color) : m_color{color}
{
	lock.acquire();
}
Logger::~Logger()
{
	DebugPort::write("\n", m_color);
	lock.release();
}

Logger& Logger::operator<<(const char* str)
{
	DebugPort::write(str, m_color);
	return *this;
}

Logger& Logger::operator<<(const String& str)
{
	DebugPort::write(str.c_str(), m_color);
	return *this;
}

Logger& Logger::operator<<(const char str)
{
	DebugPort::write(&str, m_color);
	return *this;
}

Logger& Logger::operator<<(uint64_t num)
{
	char buf[5];
	itoa(buf, num & 0xFFFFFFFF, 16);
	toupper(buf);
	DebugPort::write(buf, m_color);
	itoa(buf, num & 0xFFFFFFFF00000000, 16);
	toupper(buf);
	DebugPort::write(buf, m_color);
	return *this;
}

Logger& Logger::operator<<(int num)
{
	char buf[11];
	if (num < 0) {
		num = 0 - num;
		DebugPort::write("-", m_color);
	}

	itoa(buf, num, 10);
	toupper(buf);
	DebugPort::write(buf, m_color);
	return *this;
}

Logger& Logger::operator<<(unsigned num)
{
	char buf[11];
	itoa(buf, num, 10);
	toupper(buf);
	DebugPort::write(buf, m_color);
	return *this;
}

Logger& Logger::operator<<(Hex num)
{
	char buf[5];
	itoa(buf, num.m_data, 16);
	toupper(buf);
	DebugPort::write("0x", m_color);
	DebugPort::write(buf, m_color);
	return *this;
}

Logger& Logger::operator<<(void* ptr)
{
	char buf[5];
	itoa(buf, (int)ptr, 16);
	toupper(buf);
	DebugPort::write("0x", m_color);
	DebugPort::write(buf, m_color);
	return *this;
}<file_sep>/kernel/Utils/UniquePointer.h
#pragma once

#include "Assert.h"
#include "Stl.h"

template <typename T> class UniquePointer
{
  public:
	template <class... Args> static UniquePointer<T> make_unique(Args&&... args)
	{
		return UniquePointer(new T{forward<Args>(args)...});
	}

	explicit UniquePointer(T* ptr) : m_storage{ptr}
	{
		ASSERT(m_storage);
	}

	UniquePointer(UniquePointer&& other) : m_storage{other.m_storage}
	{
		other.m_storage = nullptr;
	}

	UniquePointer& operator=(UniquePointer&& other)
	{
		ASSERT(this != &other);
		delete m_storage;
		m_storage = other.m_storage;
		other.m_storage = nullptr;
		return *this;
	}

	UniquePointer(const UniquePointer& other) = delete;
	UniquePointer& operator=(const UniquePointer& other) = delete;
	~UniquePointer()
	{
		destroy();
	}

	T& operator*()
	{
		return *m_storage;
	}

	T* operator->()
	{
		return m_storage;
	}

	bool operator==(const UniquePointer& other)
	{
		return (m_storage == other.m_storage);
	}

	bool operator!=(const UniquePointer& other)
	{
		return (m_storage != other.m_storage);
	}

	T* release()
	{
		m_storage = nullptr;
		return m_storage;
	}

	T* reset()
	{
		T* tmp = m_storage;
		destroy();
		return tmp;
	}

	T* ptr()
	{
		return m_storage;
	}

  private:
	T* m_storage;

	void destroy()
	{
		delete m_storage;
		m_storage = nullptr;
	}
};<file_sep>/kernel/Devices/DebugPort/Logger.h
#pragma once

#include "Arch/x86/Spinlock.h"
#include "DebugPort.h"
#include "Utils/String.h"
#include "Utils/StringView.h"
#include "Utils/Types.h"

class Hex;

class Logger
{
  private:
	static StaticSpinlock lock;

  protected:
	DebugColor m_color;

  public:
	static void init();
	Logger(DebugColor color = DebugColor::White);
	~Logger();
	Logger& operator<<(const char* str);
	Logger& operator<<(const String& str);
	Logger& operator<<(const char str);
	Logger& operator<<(int num);
	Logger& operator<<(unsigned num);
	Logger& operator<<(uint64_t num);
	Logger& operator<<(Hex num);
	Logger& operator<<(void* ptr);
};

class dbg : public Logger
{
  public:
	dbg() : Logger{DebugColor::Green}
	{
	}
};

class info : public Logger
{
  public:
	info() : Logger{DebugColor::Bright_Blue}
	{
	}
};

class warn : public Logger
{
  public:
	warn() : Logger{DebugColor::Yellow}
	{
	}
};

class err : public Logger
{
  public:
	err() : Logger{DebugColor::Red}
	{
	}
};

class Hex
{
  private:
	int m_data;

  public:
	Hex(int num) : m_data(num)
	{
	}
	friend class Logger;
};<file_sep>/kernel/Filesystem/Pipes/PipeFS.cpp
#include "PipeFS.h"
#include "Tasking/ScopedLock.h"
#include "Utils/ErrorCodes.h"
#include "Utils/PathParser.h"

UniquePointer<FSNode> PipeFS::alloc(const StringView& name)
{
	return UniquePointer<FSNode>(new PipeFS(name));
}

PipeFS::PipeFS(const StringView& name) :
    FSNode(name, 0, 0, NodeType::Root, 0), //
    m_children{},
    m_lock{}
{
	// FIXME: multiple writers, one reader.
	m_lock.init();
}

PipeFS::~PipeFS()
{
}

Result<FSNode&> PipeFS::create(const StringView& name, OpenMode mode, OpenFlags flags)
{
	UNUSED(mode);
	UNUSED(flags);
	return m_children.emplace_back(name);
}

Result<FSNode&> PipeFS::dir_lookup(const StringView& file_name)
{
	for (auto& i : m_children) {
		if (i.m_name == file_name) {
			return i;
		}
	}
	return ResultError(ERROR_FILE_DOES_NOT_EXIST);
}
<file_sep>/test/PathParser.cpp
#ifdef __STRICT_ANSI__
	#undef __STRICT_ANSI__
#endif

#include "Utils/PathParser.h"
#include <gtest/gtest.h>

#define MAX_PATH_ELEMENT 256
TEST(PathParser_Test, ElementsCounting)
{
	PathParser path("/mnt/c/user/goku/rocks");
	EXPECT_EQ(path.count(), 5);
}

TEST(PathParser_Test, GettingElements)
{
	PathParser path("/mnt/fat32/c/users/goku/rocks");

	EXPECT_TRUE(path.element(0) == "mnt");
	EXPECT_TRUE(path.element(1) == "fat32");
	EXPECT_TRUE(path.element(2) == "c");
	EXPECT_TRUE(path.element(3) == "users");
	EXPECT_TRUE(path.element(4) == "goku");
	EXPECT_TRUE(path.element(5) == "rocks");
}<file_sep>/test/CircularBuffer.cpp
#ifdef __STRICT_ANSI__
	#undef __STRICT_ANSI__
#endif

#include "Utils/CircularBuffer.h"
#include <gtest/gtest.h>

TEST(CircularBuffer_Test, Initialization)
{
	const int size = 10;
	CircularBuffer<int> cb(size);
	EXPECT_EQ(cb.capacity(), 10);
	EXPECT_EQ(cb.size(), 0);
	EXPECT_TRUE(cb.is_empty());
	EXPECT_FALSE(cb.is_full());
}

TEST(CircularBuffer_Test, QueueingAndDequeueing)
{
	const int size = 10;
	CircularBuffer<int> cb(size);
	cb.queue(1);
	cb.queue(2);
	cb.queue(3);
	EXPECT_FALSE(cb.is_empty());
	EXPECT_FALSE(cb.is_full());
	EXPECT_EQ(cb.size(), 3);

	EXPECT_EQ(cb.dequeue(), 1);
	EXPECT_FALSE(cb.is_empty());
	EXPECT_FALSE(cb.is_full());
	EXPECT_EQ(cb.size(), 2);

	EXPECT_EQ(cb.dequeue(), 2);
	EXPECT_FALSE(cb.is_empty());
	EXPECT_FALSE(cb.is_full());
	EXPECT_EQ(cb.size(), 1);

	EXPECT_EQ(cb.dequeue(), 3);
	EXPECT_TRUE(cb.is_empty());
	EXPECT_FALSE(cb.is_full());
	EXPECT_EQ(cb.size(), 0);
}

TEST(CircularBuffer_Test, Wraping)
{
	const int size = 5;
	CircularBuffer<int> cb(size);
	cb.queue(1);
	cb.queue(2);
	cb.queue(3);
	cb.queue(4);
	cb.queue(5);
	EXPECT_FALSE(cb.is_empty());
	EXPECT_TRUE(cb.is_full());
	EXPECT_EQ(cb.size(), 5);

	EXPECT_EQ(cb.dequeue(), 1);
	EXPECT_FALSE(cb.is_empty());
	EXPECT_FALSE(cb.is_full());
	EXPECT_EQ(cb.size(), 4);

	cb.queue(6);
	EXPECT_FALSE(cb.is_empty());
	EXPECT_TRUE(cb.is_full());
	EXPECT_EQ(cb.size(), 5);

	EXPECT_EQ(cb.dequeue(), 2);
	EXPECT_EQ(cb.dequeue(), 3);
	EXPECT_EQ(cb.dequeue(), 4);
	EXPECT_EQ(cb.dequeue(), 5);
	EXPECT_FALSE(cb.is_empty());
	EXPECT_FALSE(cb.is_full());
	EXPECT_EQ(cb.size(), 1);

	EXPECT_EQ(cb.dequeue(), 6);
	EXPECT_TRUE(cb.is_empty());
	EXPECT_FALSE(cb.is_full());
}<file_sep>/kernel/Utils/List.h
#pragma once

#include "Rule5.h"
#include "Stl.h"
#include "Types.h"

#ifdef __UNIT_TESTS
	#include <assert.h>
	#define ASSERT(x) assert(x)
#else
	#include "Assert.h"
#endif

template <class T> class List
{
  private:
	struct Node {
		T data;
		Node *next, *prev;
	};
	Node* m_head;
	Node* m_tail;
	size_t m_count;
	void remove_node(Node& new_node);
	void append_node(Node& new_node, Node* node);
	void prepend_node(Node& new_node, Node* node);
	class Iterator
	{
	  private:
		Node* m_current;

	  public:
		Iterator(Node* t_head, size_t index);
		explicit Iterator(Node* t_list);
		Iterator(const Iterator& other);
		void operator=(const List<T>::Iterator& other);
		~Iterator() = default;

		Iterator operator++(int);
		Iterator& operator++();
		bool operator!=(const List<T>::Iterator& other);
		bool operator==(const List<T>::Iterator& other);
		T* operator->();
		T& operator*();
		friend List<T>;
	};

  public:
	NON_COPYABLE(List);
	NON_MOVABLE(List);
	List();
	~List();

	Iterator begin();
	Iterator end();
	template <typename... U> T& emplace_back(U&&... u);
	template <typename... U> T& emplace_front(U&&... u);
	T& push_back(const T& new_data);
	T& push_front(const T& new_data);
	T& push_back(T&& new_data);
	T& push_front(T&& new_data);
	void pop_back();
	void pop_front();
	void insert(const Iterator& node, const T& new_node);
	void erase(const Iterator&);
	template <class Predicate> bool remove_if(Predicate predicate);
	template <class Predicate> bool contains(Predicate predicate);
	void clear();
	void splice(List<T>& list, const Iterator& itr);
	bool is_empty() const;
	size_t size() const;
	T& head() const;
	T& tail() const;
	T& operator[](size_t index) const;
};

template <class T> List<T>::Iterator::Iterator(Node* t_head, size_t index) : m_current{t_head}
{
	while (index--) {
		m_current = m_current->next;
	}
}

template <class T> List<T>::Iterator::Iterator(const Iterator& other) : m_current{other.m_current}
{
}

template <class T> List<T>::Iterator::Iterator(Node* t_node) : m_current{t_node}
{
}

template <class T> typename List<T>::Iterator List<T>::Iterator::operator++(int arg)
{
	UNUSED(arg);
	Iterator old{*this};
	m_current = m_current->next;
	return old;
}

template <class T> typename List<T>::Iterator& List<T>::Iterator::operator++()
{
	m_current = m_current->next;
	return *this;
}

template <class T> bool List<T>::Iterator::operator!=(const List<T>::Iterator& other)
{
	return m_current != other.m_current;
}

template <class T> bool List<T>::Iterator::operator==(const List<T>::Iterator& other)
{
	return m_current == other.m_current;
}

template <class T> void List<T>::Iterator::operator=(const List<T>::Iterator& other)
{
	m_current = other->m_current;
}

template <class T> T& List<T>::Iterator::operator*()
{
	return m_current->data;
}

template <class T> T* List<T>::Iterator::operator->()
{
	return &m_current->data;
}

template <class T> List<T>::List() : m_head{nullptr}, m_tail{nullptr}, m_count{0}
{
}

template <class T> List<T>::~List()
{
	clear();
}

template <class T> void List<T>::clear()
{
	Node* node_iterator = m_head;
	while (node_iterator) {
		Node* next = node_iterator->next;
		delete node_iterator;
		node_iterator = next;
	}
	m_head = nullptr;
	m_count = 0;
}

template <class T> void List<T>::splice(List<T>& list, const Iterator& itr)
{
	remove_node(*itr.m_current);
	list.append_node(*itr.m_current, list.m_tail);
}

template <class T> void List<T>::remove_node(Node& node)
{
	if ((m_head == &node) && (m_tail == &node)) {
		m_head = m_tail = nullptr;
	} else if (m_head == &node) {
		m_head = node.next;
		node.next->prev = nullptr;
	} else if (m_tail == &node) {
		m_tail = node.prev;
		node.prev->next = nullptr;
	} else {
		node.prev->next = node.next;
		node.next->prev = node.prev;
	}
	m_count--;
}

template <class T> void List<T>::append_node(Node& new_node, Node* node)
{
	if (!m_head) {
		new_node.prev = nullptr;
		new_node.next = nullptr;
		m_head = m_tail = &new_node;
	} else {
		new_node.prev = node;
		new_node.next = node->next;
		if (node->next) {
			node->next->prev = &new_node;
		} else {
			m_tail = &new_node;
		}
		node->next = &new_node;
	}
	m_count++;
}

template <class T> void List<T>::prepend_node(Node& new_node, Node* node)
{
	if (!m_head) {
		new_node.prev = nullptr;
		new_node.next = nullptr;
		m_head = m_tail = &new_node;
	} else {
		new_node.prev = node->prev;
		new_node.next = node;
		if (node->prev) {
			node->prev->next = &new_node;
		} else {
			m_head = &new_node;
		}
		node->prev = &new_node;
	}
	m_count++;
}

template <class T> typename List<T>::Iterator List<T>::begin()
{
	return Iterator(m_head);
}

template <class T> typename List<T>::Iterator List<T>::end()
{
	return Iterator(nullptr);
}

template <class T> template <typename... U> T& List<T>::emplace_back(U&&... u)
{
	Node* new_node = new Node{T{forward<U>(u)...}, nullptr, nullptr}; // FIXME: remove T{}
	append_node(*new_node, m_tail);
	return new_node->data;
}

template <class T> template <typename... U> T& List<T>::emplace_front(U&&... u)
{
	Node* new_node = new Node{T{forward<U>(u)...}, nullptr, nullptr};
	prepend_node(*new_node, m_head);
	return new_node->data;
}

template <class T> template <class Predicate> bool List<T>::remove_if(Predicate predicate)
{
	bool is_removed = false;
	auto&& i = begin();
	while (i != end()) {
		auto iterator_copy = i++;
		if (predicate(*iterator_copy)) {
			erase(iterator_copy);
			is_removed = true;
		}
	}
	return is_removed;
}

template <class T> template <class Predicate> bool List<T>::contains(Predicate predicate)
{
	for (auto&& i : *this) {
		if (predicate(i)) {
			return true;
		}
	}
	return false;
}

template <class T> T& List<T>::push_back(const T& new_data)
{
	Node* new_node = new Node{new_data, nullptr, nullptr};
	append_node(*new_node, m_tail);
	return new_node->data;
}

template <class T> T& List<T>::push_front(const T& new_data)
{
	Node* new_node = new Node{new_data, nullptr, nullptr};
	prepend_node(*new_node, m_head);
	return new_node->data;
}

template <class T> T& List<T>::push_back(T&& new_data)
{
	Node* new_node = new Node{move(new_data), nullptr, nullptr};
	append_node(*new_node, m_tail);
	return new_node->data;
}

template <class T> T& List<T>::push_front(T&& new_data)
{
	Node* new_node = new Node{move(new_data), nullptr, nullptr};
	prepend_node(*new_node, m_head);
	return new_node->data;
}

template <class T> void List<T>::pop_back()
{
	ASSERT(m_tail);
	remove_node(*m_tail);
	delete m_tail;
}

template <class T> void List<T>::pop_front()
{
	ASSERT(m_head);
	remove_node(*m_head);
	delete m_head;
}

template <class T> void List<T>::insert(const Iterator& pos, const T& new_data)
{
	Node* new_node = new Node{new_data, nullptr, nullptr};
	append_node(*new_node, pos.m_current);
}

template <class T> void List<T>::erase(const Iterator& itr)
{
	ASSERT(itr.m_current);
	remove_node(*itr.m_current);
	delete itr.m_current;
}

template <class T> T& List<T>::head() const
{
	ASSERT(m_head);
	return m_head->data;
}

template <class T> T& List<T>::tail() const
{
	ASSERT(m_head);
	return m_tail->data;
}

template <class T> T& List<T>::operator[](size_t index) const
{
	ASSERT(index < m_count);
	Iterator itr(m_head, index);
	return *itr;
}

template <class T> bool List<T>::is_empty() const
{
	return !size();
}

template <class T> size_t List<T>::size() const
{
	return m_count;
}<file_sep>/kernel/Tests.h
#pragma once

#include "Devices/DebugPort/Logger.h"
#include "Devices/Timer/Pit.h"
#include "Filesystem/FileDescription.h"
#include "Filesystem/VirtualFilesystem.h"
#include "Tasking/Loader/PE.h"
#include "Tasking/Scheduler.h"
#include "Tasking/Semaphore.h"
#include "Utils/Bitmap.h"
#include "Utils/PathParser.h"
#include "VirtualMemory/Memory.h"

Semaphore* sem_lock;
void test_semaphore_thread2(uintptr_t arg)
{
	UNUSED(arg);
	// printf("Thread2:\n");
	sem_lock->acquire();
	// printf("Semaphore acquired by thread2\n");
	Thread::sleep(1000);
	sem_lock->release();
	// printf("Semaphore released by thread2\n");
	while (1) {
		HLT();
	}
}

void test_semaphore(uintptr_t arg)
{
	UNUSED(arg);
	// printf("Thread1:\n");
	sem_lock = new Semaphore(1);
	sem_lock->acquire();
	Thread::create_thread(Thread::current->parent_process(), test_semaphore_thread2, 0);
	// printf("Semaphore acquired by thread1\n");
	Thread::sleep(3000);
	// printf("wakeup thread1\n");
	sem_lock->release();
	// printf("Semaphore released by thread1\n");
	while (1) {
		HLT();
	}
}

/*void thread_test(uintptr_t arg)
{
    //printf("Thread %d\n", arg);
    for (size_t i = 0; i < 3; i++) {
        //printf("Thread %d:Hello %d\n", arg, i);
    }
}
void test_threading(uintptr_t arg)
{
    //printf("Main thread: creating other threads\n");
    for (size_t i = 0; i < 3; i++) {
        //printf("Main thread: Creating thread%d\n", i);
        Scheduler::create_new_thread(0, thread_test, i);
    }
}*/

void test_pipe1(uintptr_t arg)
{
	UNUSED(arg);

	auto fd = VFS::open("/fs/my_pipe2", OpenMode::Read, OpenFlags::CreateNew);
	if (fd.is_error()) {
		warn() << "error opening the file, error: " << fd.error();
		HLT();

		return;
	}
	char* buff = (char*)Memory::alloc(0xc00, MEMORY_TYPE::KERNEL | MEMORY_TYPE::WRITABLE);
	memset(buff, 0, 4096);
	auto result = fd.value()->read(buff, 12);
	dbg() << "got it, read";
	dbg() << buff;
	if (result.is_error())
		warn() << "error reading the file " << result.error();
}

void test_pipe2(uintptr_t arg)
{
	UNUSED(arg);
	Thread::sleep(1000);
	auto fd = VFS::open("/fs/my_pipe", OpenMode::Write, OpenFlags::OpenExisting);
	if (fd.is_error()) {
		warn() << "error opening the file, error: " << fd.error();
		HLT();
		return;
	}
	char* buff = (char*)Memory::alloc(0xc00, MEMORY_TYPE::KERNEL | MEMORY_TYPE::WRITABLE);
	memset(buff, 0, 4096);
	auto result = fd.value()->write(static_cast<const void*>("Hello there"), 12);
	dbg() << "got it, write";
	dbg() << buff;
	if (result.is_error())
		warn() << "error writing the file " << result.error();
}

void test_keyboard(uintptr_t arg)
{
	UNUSED(arg);

	auto fd = VFS::open("/Devices/keyboard", OpenMode::ReadWrite, OpenFlags::OpenExisting);
	if (fd.is_error()) {
		warn() << "error opening the file, error: " << fd.error();
		HLT();
		return;
	}
	char buff[1];
	while (true) {
		auto result = fd.value()->read(buff, 1);
		Logger(DebugColor::Cyan) << buff;
	}
}

void test_keyboard2(uintptr_t arg)
{
	UNUSED(arg);

	auto fd = VFS::open("/Devices/keyboard", OpenMode::ReadWrite, OpenFlags::OpenExisting);
	if (fd.is_error()) {
		warn() << "error opening the file, error: " << fd.error();
		HLT();
		return;
	}
	char buff[1];
	while (true) {
		auto result = fd.value()->read(buff, 1);
		Logger(DebugColor::Red) << buff;
	}
}

void test_console(uintptr_t arg)
{
	UNUSED(arg);

	auto fd = VFS::open("/Devices/console", OpenMode::Write, OpenFlags::OpenExisting);
	if (fd.is_error()) {
		warn() << "error opening the file, error: " << fd.error();
		HLT();
		return;
	}
	auto result = fd.value()->write("Hello there", 12);
}<file_sep>/test/Bitmap_Test.cpp
#ifdef __STRICT_ANSI__
	#undef __STRICT_ANSI__
#endif

#include "Utils/Bitmap.h"
#include <gtest/gtest.h>

TEST(Bitmap_Test, SearchForUsed)
{
	Bitmap bm(10);
	EXPECT_EQ(bm.find_first_used(5), BITMAP_NO_BITS_LEFT);
	bm.set_used(2);
	EXPECT_EQ(bm.find_first_used(5), BITMAP_NO_BITS_LEFT);
	bm.set_used(3, 4);
	EXPECT_EQ(bm.find_first_used(5), 2);
	bm.set_unused(2, 5);
	EXPECT_EQ(bm.find_first_used(5), BITMAP_NO_BITS_LEFT);
	bm.set_used(3);
	bm.set_used(6);
	EXPECT_EQ(bm.find_first_used(4), BITMAP_NO_BITS_LEFT);
}

TEST(Bitmap_Test, SearchForUnused)
{
	Bitmap bm(10);
	EXPECT_EQ(bm.find_first_unused(5), 0);
	bm.set_used(2);
	EXPECT_EQ(bm.find_first_unused(5), 3);
	bm.set_used(3, 4);
	EXPECT_EQ(bm.find_first_unused(5), BITMAP_NO_BITS_LEFT);
	bm.set_unused(2, 5);
	EXPECT_EQ(bm.find_first_unused(5), 0);
	bm.set_used(3);
	bm.set_used(6);
	EXPECT_EQ(bm.find_first_unused(4), BITMAP_NO_BITS_LEFT);
}<file_sep>/kernel/Utils/PathParser.cpp
#include "PathParser.h"
#ifdef __UNIT_TESTS
	#include <assert.h>
	#include <stdio.h>
	#include <cstring>
	#define ASSERT(x) assert(x)
#else
	#include "Lib/Stdlib.h"
	#include "Utils/Assert.h"
#endif

PathParser::PathParser(const StringView& path) : m_path{path}, m_count{calc_count()}
{
	ASSERT(is_valid());
}

PathParser::~PathParser()
{
}

size_t PathParser::count()
{
	return m_count;
}

StringView PathParser::element(size_t index)
{
	ASSERT(index < count());
	size_t pos = 0;
	size_t cur = index;
	while (cur--) {
		pos = m_path.find(SPLITER, pos + 1);
	}
	size_t len = [&]() {
		if (index == count() - 1) {
			return m_path.length() - pos - 1;
		} else {
			return m_path.find(SPLITER, pos + 1) - pos - 1;
		}
	}();

	return m_path.substr(pos + 1, len);
}

bool PathParser::is_valid()
{
	if (m_path.length() == 0)
		return false;

	if (m_path[0] != SPLITER)
		return false;

	if (m_path[m_path.length() - 1] == SPLITER)
		return false;

	return true;
}

size_t PathParser::calc_count()
{
	size_t count = 0;
	size_t last_found = 0;

	do {
		last_found = m_path.find(SPLITER, last_found + 1);
		++count;
	} while (last_found != StringView::NOT_FOUND);

	return count;
}<file_sep>/kernel/VirtualMemory/Memory.h
#pragma once

#include "Arch/x86/Isr.h"
#include "Arch/x86/Paging.h"
#include "Arch/x86/Panic.h"
#include "Arch/x86/Spinlock.h"
#include "Physical.h"
#include "Utils/Assert.h"
#include "Utils/Types.h"
#include "Virtual.h"

enum MEMORY_TYPE {
	KERNEL = 1,
	WRITABLE = 2,
	COPY_ON_WRITE = 4,
};

#define AVAILABLE_PAGES_START (GET_FRAME(0x100000))

class Memory
{
  private:
	static StaticSpinlock lock;
	static void page_fault_handler(ISRContextFrame* isr_info);
	static uint32_t parse_flags(uint32_t mem_flags);
	static void* _alloc_no_lock(uint32_t size, uint32_t flags);
	static void* _alloc_no_lock(void* virtual_address, uint32_t size, uint32_t flags);
	static void _free_no_lock(void* virtual_address, uint32_t size, uint32_t flags);
	static void* _map_no_lock(uintptr_t physical_address, uint32_t size, uint32_t flags);
	static void _unmap_no_lock(void* virtual_address, uint32_t size, uint32_t flags);
	static void setup_page_fault_handler();

  public:
	static unsigned get_kernel_pages();
	static void setup();
	static void setup_stage2();
	static void* alloc(uint32_t size, uint32_t flags);
	static void* alloc(void* virtual_address, uint32_t size, uint32_t flags);
	static void free(void* virtual_address, uint32_t size, uint32_t flags);
	static void* map(uintptr_t physical_address, uint32_t size, uint32_t flags);
	static void unmap(void* virtual_address, uint32_t size, uint32_t flags);
	static void switch_page_directory(uintptr_t physical_address);
	static uintptr_t create_new_virtual_space();
	static unsigned virtual_memory_size();
	static unsigned physical_memory_size();

	friend class VirtualMemory;
};
<file_sep>/kernel/Tasking/ScopedLock.h
#pragma once

#include "Utils/Rule5.h"

template <typename T> class ScopedLock
{
  private:
	T& m_lock;

  public:
	NON_COPYABLE(ScopedLock)
	NON_MOVABLE(ScopedLock)

	explicit ScopedLock(T& lock) : m_lock{lock}
	{
		acquire();
	}

	~ScopedLock()
	{
		release();
	}

	void release()
	{
		m_lock.release();
	}

	void acquire()
	{
		m_lock.acquire();
	}
};
<file_sep>/kernel/Filesystem/FileDescriptor.h
#pragma once

#include "Filesystem/FileDescription.h"
#include "Tasking/ScopedLock.h"
#include "Tasking/SpinLock.h"
#include "Utils/List.h"
#include "Utils/Types.h"
#include "Utils/UniquePointer.h"
#include "Utils/Stl.h"

template <class T> class Descriptor
{
  private:
	Spinlock m_lock;
	List<UniquePointer<T>> m_file_description_table; // FIXME:should be vector.

  public:
	Descriptor();
	~Descriptor();
	unsigned add_descriptor(UniquePointer<T>&& file_description);
	void remove_descriptor(unsigned);
	T& get_description(unsigned);
};

template <class T> unsigned Descriptor<T>::add_descriptor(UniquePointer<T>&& file_description)
{
	ScopedLock local_lock(m_lock);
	m_file_description_table.emplace_back(move(file_description));
	return m_file_description_table.size() - 1;
}

template <class T> void Descriptor<T>::remove_descriptor(unsigned file_descriptor)
{
	UNUSED(file_descriptor);
	ScopedLock local_lock(m_lock);
	// file_description_table.remove(file_descriptor);//FIXME:you can't just remove them.
}
template <class T> T& Descriptor<T>::get_description(unsigned file_descriptor)
{
	return *m_file_description_table[file_descriptor];
}
template <class T> Descriptor<T>::Descriptor() : m_lock{}, m_file_description_table{}
{
	m_lock.init();
}
template <class T> Descriptor<T>::~Descriptor()
{
}<file_sep>/kernel/Arch/x86/Context.h
#pragma once

#include "Gdt.h"
#include "Isr.h"
#include "Utils/Types.h"

class Context
{
  private:
	struct InitialTaskContext {
		ISRContextFrame isr_frame;
		uintptr_t return_address;
		uintptr_t argument;
	};
	static const uint32_t EFLAGS_IF_ENABLE = 0x202;

  public:
	static uint32_t setup_task_stack_context(void* stack, uint32_t stack_size, uint32_t start_function,
	                                         uint32_t return_function, uint32_t argument);
	static void switch_task_stack(uint32_t task_stack_start);
	static void enter_usermode(uintptr_t thread_address, uintptr_t thread_stack);

	static void set_return_value(ISRContextFrame* frame, uint32_t value);
	static void set_return_arg1(ISRContextFrame* frame, uint32_t value);
	static void set_return_arg2(ISRContextFrame* frame, uint32_t value);
	static void set_return_arg3(ISRContextFrame* frame, uint32_t value);

	static uint32_t syscall_num(ISRContextFrame* frame);
	static uint32_t syscall_param1(ISRContextFrame* frame);
	static uint32_t syscall_param2(ISRContextFrame* frame);
	static uint32_t syscall_param3(ISRContextFrame* frame);
	static uint32_t syscall_param4(ISRContextFrame* frame);
	static uint32_t syscall_param5(ISRContextFrame* frame);
};
<file_sep>/kernel/Filesystem/VirtualFilesystem.h
#pragma once

#include "FSNode.h"
#include "FileDescription.h"
#include "FileDescriptor.h"
#include "Utils/List.h"
#include "Utils/PathParser.h"
#include "Utils/Result.h"
#include "Utils/Types.h"
#include "Utils/UniquePointer.h"

class VFS
{
  private:
	static List<UniquePointer<FSNode>>* fs_roots;
	static Spinlock lock;

	static Result<FSNode&> traverse_parent_node(const StringView& path);
	static Result<FSNode&> traverse_node(const StringView& path);
	static Result<FSNode&> traverse_node_deep(PathParser& parser, size_t depth);
	static Result<FSNode&> open_node(const StringView& path, OpenMode mode, OpenFlags flags);
	static FSNode* get_root_node(const StringView& root_name);

  public:
	static void setup();
	static Result<UniquePointer<FileDescription>> open(const StringView& path, OpenMode mode, OpenFlags flags);
	static Result<void> mount(UniquePointer<FSNode>&& fs_root);
	static Result<void> unmount();
	static Result<void> remove();
	static Result<void> make_directory();
	static Result<void> remove_directory();
	static Result<void> rename();
	static Result<void> chown();
	static Result<void> make_link();
	static Result<void> remove_link();
};
<file_sep>/kernel/Utils/Types.h
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#define _UNUSED_PARAM(x) x tmp __attribute__((__unused__))
#define UNUSED(expr)     (void)(expr)<file_sep>/kernel/Filesystem/Pipes/Pipe.cpp
#include "Pipe.h"
#include "Tasking/ScopedLock.h"
#include "Utils/ErrorCodes.h"
#include "Utils/PathParser.h"

Pipe::Pipe(const StringView& name) :
    FSNode(name, 0, 0, NodeType::Pipe, BUFFER_SIZE),
    m_children{},
    m_buffer{BUFFER_SIZE},
    m_wait_queue{},
    m_lock{}
{
	m_lock.init();
	// FIXME: multiple writers, one reader.
}

Pipe::~Pipe()
{
}

Result<void> Pipe::open(OpenMode mode, OpenFlags flags)
{
	UNUSED(mode);
	UNUSED(flags);
	return ResultError(ERROR_SUCCESS);
}

Result<void> Pipe::close()
{
	return ResultError(ERROR_SUCCESS);
}

Result<void> Pipe::read(void* buff, size_t offset, size_t size)
{
	UNUSED(offset);

	ScopedLock local_lock(m_lock);
	while (m_buffer.size() < size) {
		local_lock.release();
		Thread::current->wait_on(m_wait_queue);
		local_lock.acquire();
	}

	char* _buf = static_cast<char*>(buff);
	for (size_t i = 0; i < size; i++) {
		_buf[i] = m_buffer.dequeue();
	}

	m_wait_queue.wake_up();
	return ResultError(ERROR_SUCCESS);
}

Result<void> Pipe::write(const void* buff, size_t offset, size_t size)
{
	UNUSED(offset);

	ScopedLock local_lock(m_lock);
	if (m_buffer.available_size() < size) {
		local_lock.release();
		Thread::current->wait_on(m_wait_queue);
		local_lock.acquire();
	}

	const char* _buf = static_cast<const char*>(buff);
	for (size_t i = 0; i < size; i++) {
		m_buffer.queue(_buf[i]);
	}

	m_wait_queue.wake_up();
	return ResultError(ERROR_SUCCESS);
}

Result<bool> Pipe::can_read()
{
	return m_buffer.is_empty();
}

Result<bool> Pipe::can_write()
{
	return m_buffer.is_full();
}

Result<void> Pipe::remove()
{
	return ResultError(ERROR_INVALID_OPERATION);
}
<file_sep>/kernel/Tasking/WaitQueue.cpp
#include "WaitQueue.h"

WaitQueue::WaitQueue() : m_lock{}, m_threads{}
{
}

WaitQueue::~WaitQueue()
{
}

void WaitQueue::enqueue(Thread& thread)
{
	m_threads.push_back(thread);
}

void WaitQueue::wake_up()
{
	if (!m_threads.size()) {
		return;
	}
	auto* thread_to_wake = m_threads.pop_front();
	if (thread_to_wake)
		thread_to_wake->wake_up_from_queue();
}

void WaitQueue::wake_up(size_t num)
{
	while ((num--) && (!m_threads.is_empty())) {
		wake_up();
	}
}

void WaitQueue::wake_up_all()
{
	while (!m_threads.is_empty()) {
		wake_up();
	}
}<file_sep>/kernel/Devices/Keyboard/Keyboard.cpp
#include "Keyboard.h"
#include "Arch/x86/Asm.h"
#include "Tasking/ScopedLock.h"
#include "Tasking/SpinLock.h"
#include "Utils/ErrorCodes.h"

Keyboard* Keyboard::current_instance = nullptr;

UniquePointer<FSNode> Keyboard::alloc(const StringView& name)
{
	return UniquePointer<FSNode>(new Keyboard(name));
}

Keyboard::Keyboard(const StringView& name) :
    FSNode{name, 0, 0, NodeType::Device, 1024},
    m_lock{},
    m_wait_queue{},
    m_buffer{1024},
    pressed_keys{false, false, false}
{
	ASSERT(current_instance == nullptr);

	current_instance = this;
	m_lock.init();
	PIC::enable_irq(PIC_KEYBOARD);
	ISR::register_isr_handler(keyboard_driver_handler, PIC_KEYBOARD + PIC1_IDT_OFFSET);
}

Keyboard::~Keyboard()
{
}

Result<void> Keyboard::open(OpenMode mode, OpenFlags flags)
{
	UNUSED(mode);
	UNUSED(flags);

	return ResultError(ERROR_SUCCESS);
}

Result<void> Keyboard::close()
{
	return ResultError(ERROR_SUCCESS);
}

Result<void> Keyboard::read(void* buff, size_t offset, size_t size)
{
	UNUSED(offset);

	ScopedLock local_lock(m_lock);
	while (m_buffer.size() < size) {
		local_lock.release();
		Thread::current->wait_on(m_wait_queue);
		local_lock.acquire();
	}

	char* _buf = static_cast<char*>(buff);
	for (size_t i = 0; i < size; i++) {
		_buf[i] = m_buffer.dequeue();
	}

	return ResultError(ERROR_SUCCESS);
}

Result<bool> Keyboard::can_read()
{
	ScopedLock local_lock(m_lock);
	return m_buffer.is_empty();
}

void Keyboard::enqueue_keystoke(unsigned char data)
{
	ScopedLock local_lock(m_lock);
	if (data == 0x2A) // SHIFT Pressed
	{
		pressed_keys[0] = 1;
	} else if (data == 0xAA) { // SHIFT Released
		pressed_keys[0] = 0;
	} else if ((data & 0x80) == 0) {
		if (m_buffer.is_full()) {
			m_buffer.dequeue(); // memory is full get rid of old keyboard strokes.
		}
		m_buffer.queue(asccode[data][pressed_keys[0]]);
		m_wait_queue.wake_up_all();
	}
}

void Keyboard::keyboard_driver_handler(ISRContextFrame* frame)
{
	UNUSED(frame);
	current_instance->enqueue_keystoke(in8(KBD_DATA_PORT));
	PIC::acknowledge_pic(PIC_PIT);
}<file_sep>/kernel/VirtualMemory/Memory.cpp
#include "Memory.h"
#include "Tasking/ScopedLock.h"

StaticSpinlock Memory::lock;
void Memory::setup()
{
	lock.init();
	Paging::setup(get_kernel_pages());
	PhysicalMemory::initialize();
	PhysicalMemory::set_used_pages(GET_FRAME(KERNEL_PHYSICAL_ADDRESS), get_kernel_pages());
}

void Memory::setup_stage2()
{
	setup_page_fault_handler();
}

void Memory::setup_page_fault_handler()
{
	ISR::register_isr_handler(page_fault_handler, IRQ_NUMBER::PF);
}

void Memory::page_fault_handler(ISRContextFrame* isr_info)
{
	// printf("Page= %X EIP=%X\t CS=%X\t ESP=%X \t\n", get_faulted_page(), isr_info->eip, isr_info->cs,
	// isr_info->registers.esp);
	if (!PF_PRESENT(isr_info->error_code)) {
		PANIC("Page fault due accessing non-present page.");
	} else if (PF_US(isr_info->error_code)) {
		PANIC("Page fault due accessing kernel page from user mode.");
	} else if (PF_WR(isr_info->error_code)) {
		PANIC("Page fault due writing to read only page.");
	}
}

void* Memory::alloc(uint32_t size, uint32_t flags)
{
	ScopedLock local_lock(lock);
	void* vAdd = _alloc_no_lock(size, flags);
	return vAdd;
}

void* Memory::alloc(void* virtual_address, uint32_t size, uint32_t flags)
{
	ScopedLock local_lock(lock);
	void* vAdd = _alloc_no_lock(virtual_address, size, flags);
	return vAdd;
}

void Memory::free(void* virtual_address, uint32_t size, uint32_t flags)
{
	ScopedLock local_lock(lock);
	_free_no_lock(virtual_address, size, flags);
}

void* Memory::map(uintptr_t physical_address, uint32_t size, uint32_t flags)
{
	ScopedLock local_lock(lock);
	void* vAdd = _map_no_lock(physical_address, size, flags);
	return vAdd;
}

void Memory::unmap(void* virtual_address, uint32_t size, uint32_t flags)
{
	ScopedLock local_lock(lock);
	_unmap_no_lock(virtual_address, size, flags);
}

uintptr_t Memory::create_new_virtual_space()
{

	uintptr_t page_directory = (uintptr_t)alloc(sizeof(PAGE_DIRECTORY), MEMORY_TYPE::WRITABLE | MEMORY_TYPE::KERNEL);
	ScopedLock local_lock(lock);
	Paging::map_kernel_pd_entries(page_directory);
	Paging::unmap_pages(page_directory,
	                    GET_PAGES(sizeof(PAGE_DIRECTORY))); // unmap pd from virtual memory but keep it in physical
	uintptr_t physical_address = Paging::get_physical_page(page_directory) * PAGE_SIZE;
	return physical_address;
}

unsigned Memory::virtual_memory_size()
{
	ScopedLock local_lock(lock);
	ASSERT_NOT_REACHABLE();
	return 0;
}

unsigned Memory::physical_memory_size()
{
	ScopedLock local_lock(lock);
	return PhysicalMemory::get_physical_memory_size();
}

unsigned Memory::get_kernel_pages()
{
	uintptr_t kernel_size = uintptr_t(&KERNEL_END) - uintptr_t(&KERNEL_START) - 1;
	return GET_PAGES(kernel_size);
}

uint32_t Memory::parse_flags(uint32_t mem_flags)
{
	uint32_t page_flags = PAGE_FLAGS_PRESENT;
	if (mem_flags & MEMORY_TYPE::WRITABLE) {
		page_flags |= PAGE_FLAGS_WRITABLE;
	}
	if (!(mem_flags & MEMORY_TYPE::KERNEL)) {
		page_flags |= PAGE_FLAGS_USER;
	}
	return page_flags;
}
void Memory::switch_page_directory(uintptr_t physical_address)
{
	Paging::load_page_directory(physical_address);
}

void* Memory::_map_no_lock(uintptr_t physical_address, uint32_t size, uint32_t flags)
{
	uintptr_t vAdd;
	uintptr_t padding = physical_address % PAGE_SIZE;
	uintptr_t aligned_physical_address = physical_address - padding;
	uintptr_t pAdd = GET_FRAME((uintptr_t)aligned_physical_address);
	size_t pages_num = GET_PAGES(size);

	if (padding)
		pages_num++;

	if (!size) {
		return nullptr;
	}

	if (!PhysicalMemory::check_free_pages(pAdd, pages_num))
		return nullptr;

	if (flags & MEMORY_TYPE::KERNEL) {
		vAdd = VirtualMemory::find_pages(KERNEL_VIRTUAL_ADDRESS, LAST_PAGE_ADDRESS, pages_num);
	} else {
		vAdd = VirtualMemory::find_pages(FIRST_PAGE_ADDRESS, KERNEL_VIRTUAL_ADDRESS,
		                                 pages_num); // skip first page to detect null pointer
	}

	PhysicalMemory::set_used_pages(pAdd, pages_num);
	VirtualMemory::map_pages(vAdd, aligned_physical_address, GET_PAGES(size), parse_flags(flags));
	return (void*)(vAdd + padding);
}

void Memory::_unmap_no_lock(void* virtual_address, uint32_t size, uint32_t flags)
{
	_free_no_lock(virtual_address, size, flags);
}

void Memory::_free_no_lock(void* virtual_address, uint32_t size, uint32_t flags)
{
	UNUSED(flags);
	unsigned pages_num = GET_PAGES(size);
	uintptr_t pAdd = Paging::get_physical_page((uintptr_t)virtual_address);
	PhysicalMemory::free_pages(pAdd, pages_num);
	Paging::unmap_pages((uintptr_t)virtual_address, pages_num);
}

void* Memory::_alloc_no_lock(void* virtual_address, uint32_t size, uint32_t flags)
{
	uintptr_t vAdd;
	unsigned pages_num = GET_PAGES(size);
	vAdd = (uintptr_t)virtual_address;
	if (!VirtualMemory::check_free_pages(vAdd, pages_num)) {
		return nullptr;
	}
	for (size_t i = 0; i < pages_num; i++) {
		uintptr_t pAdd = PhysicalMemory::alloc_page(AVAILABLE_PAGES_START);
		VirtualMemory::map_pages(vAdd + (PAGE_SIZE * i), pAdd, 1, parse_flags(flags));
	}
	return (void*)vAdd;
}

void* Memory::_alloc_no_lock(uint32_t size, uint32_t flags)
{
	uintptr_t vAdd;
	unsigned pages_num = GET_PAGES(size);

	if (flags & MEMORY_TYPE::KERNEL) {
		vAdd = VirtualMemory::find_pages(KERNEL_VIRTUAL_ADDRESS, LAST_PAGE_ADDRESS, pages_num);
	} else {
		vAdd = VirtualMemory::find_pages(FIRST_PAGE_ADDRESS, KERNEL_VIRTUAL_ADDRESS,
		                                 pages_num); // skip first page to detect null pointer
	}

	for (size_t i = 0; i < pages_num; i++) {

		uintptr_t pAdd = PhysicalMemory::alloc_page(AVAILABLE_PAGES_START);
		VirtualMemory::map_pages(vAdd + (PAGE_SIZE * i), pAdd, 1, parse_flags(flags));
	}
	return (void*)vAdd;
}<file_sep>/kernel/Tasking/SystemCall.h
#pragma once
#include "Arch/x86/Context.h"
#include "Utils/Result.h"
#include "Utils/Types.h"

typedef Result<int> (*generic_syscall)(int arg0, int arg1, int arg2, int arg3, int arg4);

class SystemCall
{
  private:
	static generic_syscall systemcalls_routines[];
	static unsigned syscalls_count;

	static generic_syscall get_syscall_routine(unsigned syscall_num);
	static void systemcall_handler(ISRContextFrame* frame);

  public:
	static void setup();
};

Result<int> OpenFile(char* path, int mode, int flags);
Result<int> ReadFile(unsigned descriptor, void* buff, size_t size);
Result<int> WriteFile(unsigned descriptor, void* buff, size_t size);
Result<int> CloseFile(unsigned descriptor);

Result<int> CreateThread(void* address, int arg);
Result<int> CreateRemoteThread(int process, void* address, int arg);
Result<int> CreateProcess(char* name, char* path, int flags);
Result<int> Sleep(size_t size);
Result<int> Yield();<file_sep>/kernel/Utils/Bitmap.h
#pragma once

#include "Types.h"

#define MAX_BITMAP_SIZE       24576
#define CHECK_BIT(value, bit) ((value >> bit) & 1)
#define BITMAP_NO_BITS_LEFT   0xFFFFFFFF

class Bitmap
{
  private:
	uint8_t* m_bitmap_data;
	size_t m_size;

  public:
	Bitmap(size_t size);
	~Bitmap();
	void set_used(unsigned position);
	void set_unused(unsigned position);
	void set_used(unsigned position, unsigned count);
	void set_unused(unsigned position, unsigned count);
	unsigned find_first_unused(unsigned count);
	unsigned find_first_used(unsigned count);
	unsigned find_first_unused();
	unsigned find_first_used();
};
<file_sep>/kernel/Arch/x86/Gdt.cpp
#include "Gdt.h"

volatile GDT_DESCRIPTOR GDT::gdt __attribute__((aligned(8)));
volatile GDT_ENTRY GDT::gdt_entries[GDT_NUMBER_OF_ENTRIES] __attribute__((aligned(PAGE_SIZE)));
volatile TSS_ENTRY GDT::tss_entry __attribute__((aligned(PAGE_SIZE)));
void GDT::setup()
{
	memset((void*)&tss_entry, 0, sizeof(TSS_ENTRY));
	memset((void*)&gdt_entries, 0, sizeof(GDT_ENTRY) * GDT_NUMBER_OF_ENTRIES);

	fill_gdt((uint32_t)&gdt_entries, GDT_NUMBER_OF_ENTRIES * sizeof(GDT_ENTRY) - 1);

	// Empty Entry
	fill_gdt_entry(0, 0, 0, 0, 0);
	// Kernel Segments
	fill_gdt_entry(SEGMENT_INDEX(KCS_SELECTOR), 0, 0xFFFFF, GDT_CODE_PL0, 0x0D);
	fill_gdt_entry(SEGMENT_INDEX(KDS_SELECTOR), 0, 0xFFFFF, GDT_DATA_PL0, 0x0D);
	// User Entries
	fill_gdt_entry(SEGMENT_INDEX(UCS_SELECTOR), 0, 0xFFFFF, GDT_CODE_PL3, 0x0D);
	fill_gdt_entry(SEGMENT_INDEX(UDS_SELECTOR), 0, 0xFFFFF, GDT_DATA_PL3, 0x0D);
	// TSS
	fill_gdt_entry(SEGMENT_INDEX(TSS_SELECTOR), uint32_t(&tss_entry), sizeof(TSS_ENTRY), GDT_TSS_PL3, 0);

	load_gdt();

	load_segments(KCS_SELECTOR, KDS_SELECTOR);
	setup_tss(0);
}

void GDT::set_tss_stack(uint32_t kernel_stack)
{
	memset((void*)&tss_entry, 0, sizeof(TSS_ENTRY));
	tss_entry.esp0 = kernel_stack;
	tss_entry.ss0 = KDS_SELECTOR;
}

void GDT::setup_tss(uint32_t kernel_stack)
{
	set_tss_stack(kernel_stack);
	load_tss(TSS_SELECTOR);
}

void GDT::fill_gdt_entry(uint32_t gdt_entry, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
{
	gdt_entries[gdt_entry].base0_15 = base & 0x0000FFFF;
	gdt_entries[gdt_entry].base16_23 = (base & 0x00FF0000) >> 16;
	gdt_entries[gdt_entry].base24_31 = (base & 0xFF000000) >> 24;
	gdt_entries[gdt_entry].lim0_15 = limit & 0xFFFF;
	gdt_entries[gdt_entry].lim16_19 = (limit & 0x0F0000) >> 16;
	gdt_entries[gdt_entry].access = access;
	gdt_entries[gdt_entry].flags = flags;
}

void GDT::fill_gdt(uint32_t base, uint16_t limit)
{
	gdt.base = base;
	gdt.limit = limit;
}

void GDT::load_gdt()
{
	asm volatile("LGDT [%0]" : : "r"(&gdt));
}

void GDT::load_tss(uint16_t tss)
{
	asm volatile("LTR %0" : : "a"(tss));
}

void GDT::load_segments(uint16_t code_segment, uint16_t data_segment)
{
	asm volatile("MOV %%ds,%0;"
	             "MOV %%es,%0;"
	             "MOV %%ss,%0;"
	             "MOV %%fs,%0;"
	             "MOV %%gs,%0;"
	             :
	             : "r"(data_segment));

	asm volatile("PUSH %0;"
	             "PUSH OFFSET far_jmp;"
	             "RETF;"
	             "far_jmp:"
	             :
	             : "r"((uint32_t)code_segment));
}
<file_sep>/kernel/Utils/PathParser.h
#pragma once
#include "Utils/StringView.h"
#define SPLITER '/'
class PathParser
{
  private:
	const StringView m_path;
	const size_t m_count;
	size_t calc_count();

  public:
	explicit PathParser(const StringView& path);
	~PathParser();
	size_t count();
	StringView element(size_t index);
	bool is_valid();
};<file_sep>/kernel/Arch/x86/Context.cpp
#include "Context.h"

uint32_t Context::setup_task_stack_context(void* stack, uint32_t stack_size, uint32_t start_function,
                                           uint32_t return_function, uint32_t argument)
{
	InitialTaskContext* context =
	    reinterpret_cast<InitialTaskContext*>(uintptr_t(stack) + stack_size - sizeof(InitialTaskContext));
	context->return_address = return_function;
	context->argument = argument;
	context->isr_frame.eip = start_function;
	context->isr_frame.cs = KCS_SELECTOR;
	context->isr_frame.eflags = EFLAGS_IF_ENABLE;
	return uint32_t(&context->isr_frame) + 4;
}

void Context::switch_task_stack(uint32_t task_stack_start)
{
	GDT::set_tss_stack(task_stack_start);
}

void Context::enter_usermode(uintptr_t address, uintptr_t stack)
{
	asm volatile("MOV %%ds,%0;"
	             "MOV %%es,%0;"
	             "MOV %%fs,%0;"
	             "MOV %%gs,%0;"
	             "PUSH %0;"
	             "PUSH %1;"
	             "PUSH %2;"
	             "PUSH %3;"
	             "PUSH %4;"
	             "IRET;"
	             :
	             : "r"(uint16_t{UDS_SELECTOR}), "r"(uint32_t{stack}), "i"(uint32_t{EFLAGS_IF_ENABLE}),
	               "r"(uint32_t{UCS_SELECTOR}), "r"(uint32_t{address}));
}

void Context::set_return_value(ISRContextFrame* frame, uint32_t value)
{
	frame->registers.eax = value;
}

void Context::set_return_arg1(ISRContextFrame* frame, uint32_t value)
{
	frame->registers.ecx = value;
}

void Context::set_return_arg2(ISRContextFrame* frame, uint32_t value)
{
	frame->registers.edx = value;
}

void Context::set_return_arg3(ISRContextFrame* frame, uint32_t value)
{
	frame->registers.ebx = value;
}

uint32_t Context::syscall_num(ISRContextFrame* frame)
{
	return frame->registers.eax;
}

uint32_t Context::syscall_param1(ISRContextFrame* frame)
{
	return frame->registers.ecx;
}

uint32_t Context::syscall_param2(ISRContextFrame* frame)
{
	return frame->registers.edx;
}

uint32_t Context::syscall_param3(ISRContextFrame* frame)
{
	return frame->registers.ebx;
}

uint32_t Context::syscall_param4(ISRContextFrame* frame)
{
	return frame->registers.esi;
}

uint32_t Context::syscall_param5(ISRContextFrame* frame)
{
	return frame->registers.edi;
}