]> code.bitgloo.com Git - clyne/osdev.git/commitdiff
reorganize files
authorClyne Sullivan <clyne@bitgloo.com>
Mon, 30 Sep 2024 15:08:46 +0000 (11:08 -0400)
committerClyne Sullivan <clyne@bitgloo.com>
Mon, 30 Sep 2024 15:08:46 +0000 (11:08 -0400)
58 files changed:
.gitignore
Makefile
acpi.cpp [deleted file]
acpi.hpp [deleted file]
ata.cpp [deleted file]
ata.hpp [deleted file]
boot.cpp [deleted file]
circularbuffer.hpp [deleted file]
gdt.cpp [deleted file]
gdt.hpp [deleted file]
idt.cpp [deleted file]
idt.hpp [deleted file]
kernel.cpp [deleted file]
keyboard.cpp [deleted file]
keyboard.hpp [deleted file]
memmove.cpp [deleted file]
memory.cpp [deleted file]
memory.hpp [deleted file]
multiboot.cpp [deleted file]
multiboot.hpp [deleted file]
pic.cpp [deleted file]
pic.hpp [deleted file]
pit.cpp [deleted file]
pit.hpp [deleted file]
portio.hpp [deleted file]
src/acpi.cpp [new file with mode: 0644]
src/acpi.hpp [new file with mode: 0644]
src/ata.cpp [new file with mode: 0644]
src/ata.hpp [new file with mode: 0644]
src/boot.cpp [new file with mode: 0644]
src/circularbuffer.hpp [new file with mode: 0644]
src/gdt.cpp [new file with mode: 0644]
src/gdt.hpp [new file with mode: 0644]
src/idt.cpp [new file with mode: 0644]
src/idt.hpp [new file with mode: 0644]
src/kernel.cpp [new file with mode: 0644]
src/keyboard.cpp [new file with mode: 0644]
src/keyboard.hpp [new file with mode: 0644]
src/memmove.cpp [new file with mode: 0644]
src/memory.cpp [new file with mode: 0644]
src/memory.hpp [new file with mode: 0644]
src/multiboot.cpp [new file with mode: 0644]
src/multiboot.hpp [new file with mode: 0644]
src/pic.cpp [new file with mode: 0644]
src/pic.hpp [new file with mode: 0644]
src/pit.cpp [new file with mode: 0644]
src/pit.hpp [new file with mode: 0644]
src/portio.hpp [new file with mode: 0644]
src/tasking.cpp [new file with mode: 0644]
src/tasking.hpp [new file with mode: 0644]
src/textoutput.hpp [new file with mode: 0644]
src/vgaterminal.cpp [new file with mode: 0644]
src/vgaterminal.hpp [new file with mode: 0644]
tasking.cpp [deleted file]
tasking.hpp [deleted file]
textoutput.hpp [deleted file]
vgaterminal.cpp [deleted file]
vgaterminal.hpp [deleted file]

index 540202a58c0177944f1e763f3b83db3ed3298900..afda4deeaea8f8364885fe40eb705178c8c6b315 100644 (file)
@@ -1,5 +1,4 @@
-*.bin
 *.iso
-*.o
 *.sw*
 iso/boot/*.bin
+out
index 728ead610a591f2736d58d6b955998bbacc1f04c..2484913f5806d3e6d2c9725fc9670729bbb744c1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,43 +2,35 @@ CXXFLAGS := -m32 -ggdb -g3 -O1 -fno-pic -fno-rtti -fno-exceptions -std=c++23 \
             -Wall -Wextra -pedantic -Werror
 LDFLAGS := $(CXXFLAGS) -T link.ld -static -nostdlib -fno-use-cxa-atexit
 
-CXXFILES := acpi.cpp \
-        ata.cpp \
-        boot.cpp \
-        gdt.cpp \
-        idt.cpp \
-        keyboard.cpp \
-        memmove.cpp \
-        memory.cpp \
-        multiboot.cpp \
-        pic.cpp \
-        pit.cpp \
-        tasking.cpp \
-        vgaterminal.cpp \
-        kernel.cpp
-
-OBJS := $(subst .cpp,.o,$(CXXFILES))
-
-all: myos.iso
-
-myos.iso: myos.bin iso/boot/grub/grub.cfg
+CXXFILES := $(wildcard src/*.cpp)
+
+PROJECT := myos
+PRJISO := $(PROJECT).iso
+PRJBIN := $(PROJECT).bin
+OBJS := $(patsubst src/%.cpp,out/%.o,$(CXXFILES))
+
+all: $(PRJISO)
+
+$(PRJISO): iso/boot/$(PRJBIN) iso/boot/grub/grub.cfg
        @echo "  ISO " $@
-       @cp myos.bin iso/boot/
-       @grub-mkrescue -o myos.iso iso/
+       @grub-mkrescue -o $@ iso/
 
-myos.bin: $(OBJS) link.ld
+iso/boot/$(PRJBIN): $(OBJS) link.ld
        @echo "  LD  " $@
        @g++ $(LDFLAGS) -o $@ $(OBJS)
 
-%.o: %.cpp
+out/:
+       @mkdir out
+
+out/%.o: src/%.cpp
        @echo "  CXX " $<
        @g++ $(CXXFLAGS) -c $< -o $@
 
 clean:
        @echo "  CLEAN"
-       @rm -f $(OBJS) myos.bin myos.iso
+       @rm -f $(OBJS) $(PRJBIN) $(PRJISO)
 
 run: myos.iso
        @echo "  QEMU"
-       @qemu-system-i386 -drive file=$<,index=2,media=cdrom -monitor stdio -no-reboot -s -S #-d int
+       @qemu-system-i386 -drive file=$<,index=2,media=cdrom -monitor stdio -no-reboot #-s -S #-d int
 
diff --git a/acpi.cpp b/acpi.cpp
deleted file mode 100644 (file)
index b74a7dc..0000000
--- a/acpi.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "textoutput.hpp"
-
-#include <cstdint>
-
-extern TextOutput& term;
-extern std::uint32_t *acpiRsdp;
-extern std::uint32_t *acpiRsdpV2;
-
-struct XSDP {
-   char Signature[8];
-   std::uint8_t Checksum;
-   char OEMID[6];
-   std::uint8_t Revision;
-   std::uint32_t RsdtAddress;      // deprecated since version 2.0
-
-   // v2 only!
-   std::uint32_t Length;
-   std::uint64_t XsdtAddress;
-   std::uint8_t ExtendedChecksum;
-   std::uint8_t reserved[3];
-} __attribute__ ((packed));
-
-struct SDTHeader {
-    char Signature[4];
-    std::uint32_t Length;
-    std::uint8_t Revision;
-    std::uint8_t Checksum;
-    char OEMID[6];
-    char OEMTableID[8];
-    std::uint32_t OEMRevision;
-    std::uint32_t CreatorID;
-    std::uint32_t CreatorRevision;
-};
-
-static XSDP *rsdp = nullptr;
-
-void acpi_initialize()
-{
-    if (acpiRsdp) {
-        term.write("ACPI v1 detected.\n");
-        rsdp = reinterpret_cast<XSDP *>(acpiRsdp);
-    } else if (acpiRsdpV2) {
-        term.write("ACPI v2 detected, treating as v1.\n");
-        rsdp = reinterpret_cast<XSDP *>(acpiRsdpV2);
-    }
-
-    //if (rsdp) {
-    //    auto sdt = reinterpret_cast<SDTHeader *>(rsdp->RsdtAddress);
-    //}
-}
-
diff --git a/acpi.hpp b/acpi.hpp
deleted file mode 100644 (file)
index 8154b81..0000000
--- a/acpi.hpp
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef ACPI_HPP
-#define ACPI_HPP
-
-void acpi_initialize();
-
-#endif // ACPI_HPP
-
diff --git a/ata.cpp b/ata.cpp
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/ata.hpp b/ata.hpp
deleted file mode 100644 (file)
index 5394c31..0000000
--- a/ata.hpp
+++ /dev/null
@@ -1,131 +0,0 @@
-#ifndef ATA_HPP
-#define ATA_HPP
-
-#include "portio.hpp"
-
-#include <cstdint>
-#include <utility>
-
-namespace ATA
-{
-    enum class Type {
-        None,
-        ATA,
-        ATAPI
-    };
-
-    enum class Base : std::uint16_t {
-        Primary = 0x01F0,
-        Secondary = 0x0170
-    };
-
-    enum class Drive : std::uint8_t {
-        Master = 0xA0,
-        Slave = 0xB0
-    };
-
-    enum class Command : std::uint8_t {
-        Identify = 0xEC,
-        IdentifyPacketDevice = 0xA1
-    };
-
-    namespace Status {
-        static constexpr std::uint8_t Busy  = 0x80;
-        static constexpr std::uint8_t Ready = 0x40;
-        static constexpr std::uint8_t DF    = 0x20;
-        static constexpr std::uint8_t DSC   = 0x10;
-        static constexpr std::uint8_t DRQ   = 0x08;
-        static constexpr std::uint8_t CORR  = 0x04;
-        static constexpr std::uint8_t Index = 0x02;
-        static constexpr std::uint8_t Error = 0x01;
-    }
-
-    static constexpr std::uint8_t ATAPIIdentify0 = 0x14;
-    static constexpr std::uint8_t ATAPIIdentify1 = 0xEB;
-
-    using enum Base;
-    using enum Drive;
-
-    template<Base PBase>
-    struct Bus
-    {
-        template<Base b, unsigned offs>
-        using BPort = Port<std::to_underlying(b) + offs>;
-
-        [[no_unique_address]] BPort<PBase, 0> data;
-        [[no_unique_address]] BPort<PBase, 1> errFeats;
-        [[no_unique_address]] BPort<PBase, 2> count;
-        [[no_unique_address]] BPort<PBase, 3> lba0;
-        [[no_unique_address]] BPort<PBase, 4> lba1;
-        [[no_unique_address]] BPort<PBase, 5> lba2;
-        [[no_unique_address]] BPort<PBase, 6> select;
-        [[no_unique_address]] BPort<PBase, 7> cmdStat;
-
-        Type identify(Drive drv) {
-            auto type = Type::None;
-
-            data = std::to_underlying(drv);
-            count = '\0';
-            lba0 = '\0';
-            lba1 = '\0';
-            lba2 = '\0';
-            cmdStat = std::to_underlying(Command::Identify);
-    
-            if (cmdStat == '\0')
-                return type;
-
-            type = Type::ATA;
-            while (cmdStat & Status::Busy);
-
-            std::uint8_t stat;
-            do {
-                stat = cmdStat;
-
-                if (stat & Status::Error) {
-                    if (lba1 == ATAPIIdentify0 && lba2 == ATAPIIdentify1) {
-                        type = identifyAtapi(drv);
-                        break;
-                    } else {
-                        return type;
-                    }
-                }
-            } while (!(stat & Status::DRQ));
-
-            if (type != Type::None) {
-                for (int i = 0; i < 256; ++i) {
-                    volatile std::uint16_t w = data;
-                    (void)w;
-                }
-            }
-
-            return type;
-        }
-
-        Type identifyAtapi(Drive drv) {
-            data = std::to_underlying(drv);
-            count = '\0';
-            lba0 = '\0';
-            lba1 = '\0';
-            lba2 = '\0';
-            cmdStat = std::to_underlying(Command::IdentifyPacketDevice);
-    
-            if (cmdStat == '\0')
-                return Type::None;
-
-            while (cmdStat & Status::Busy);
-
-            std::uint8_t stat;
-            do {
-                stat = cmdStat;
-
-                if (stat & Status::Error)
-                    return Type::None;
-            } while (!(stat & Status::DRQ));
-
-            return Type::ATAPI;
-        }
-    };
-} // ATA
-
-#endif // ATA_HPP
-
diff --git a/boot.cpp b/boot.cpp
deleted file mode 100644 (file)
index 6b1da6a..0000000
--- a/boot.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <array>
-#include <cstdint>
-#include <span>
-
-extern void (*__init_array_start)();
-extern void (*__init_array_end)();
-extern void kernel_main();
-
-alignas(16)
-static std::array<std::uint8_t, 16384> stack;
-
-static void init_array()
-{
-    std::span initArray (&__init_array_start, &__init_array_end);
-    for (auto& fn : initArray)
-        fn();
-}
-
-extern "C"
-__attribute__((naked))
-void _start()
-{
-    asm volatile(R"(
-        mov %%eax, multiboot_magic
-        mov %%ebx, multiboot_ptr
-        mov %0, %%esp
-    )" :: "i" (stack.data() + stack.size()));
-
-    init_array();
-    kernel_main();
-
-    asm volatile("cli");
-    for (;;)
-        asm volatile("hlt");
-}
-
diff --git a/circularbuffer.hpp b/circularbuffer.hpp
deleted file mode 100644 (file)
index 64a9e48..0000000
+++ /dev/null
@@ -1,573 +0,0 @@
-/*
-MIT License
-
-Copyright (c) 2020 Vinit James
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-#ifndef CIRCULAR_BUFFER_H
-#define CIRCULAR_BUFFER_H
-
-#include <algorithm>
-#include <iterator>
-#include <mutex>
-#include <memory>
-#include <stdexcept>
-#include <utility>
-
-
-template<typename T>
-class CircularBuffer {
-private:
-       
-       typedef T* pointer;
-       typedef const T* const_pointer;
-       typedef T& reference;
-       typedef const T& const_reference;
-       typedef size_t size_type;
-       typedef ptrdiff_t difference_type;
-    template <bool isConst> struct BufferIterator;
-       
-
-public:
-    typedef T value_type;
-
-    // clyne
-    constexpr CircularBuffer()
-        :_buff{}, _max_size{0} {}
-
-       explicit CircularBuffer(size_t size)
-               :_buff{std::unique_ptr<T[]>(new value_type[size])}, _max_size{size}{}
-
-       CircularBuffer(const CircularBuffer& other)
-               :_buff{std::unique_ptr<T[]>(new value_type[other._max_size])},
-                _max_size{other._max_size},
-                _size{other._size},
-                _head{other._head},
-                _tail{other._tail}{
-                        std::copy(other.data(), other.data() + _max_size, _buff.get());
-                }
-
-       
-       CircularBuffer& operator=(const CircularBuffer& other){
-               if ( this != &other){
-                       _buff.reset(new value_type[other._max_size]);
-                       _max_size = other._max_size;
-                       _size = other._size;
-                       _head = other._head;
-                       _tail = other._tail;
-                       std::copy(other.data(), other.data() + _max_size, _buff.get());
-               }
-               return *this;
-       }
-
-       CircularBuffer(CircularBuffer&& other) noexcept
-               :_buff{std::move(other._buff)},
-                _max_size{other._max_size},
-                _size{other._size},
-                _head{other._head},
-                _tail{other._tail}{
-
-               other._buff = nullptr;
-               other._max_size = 0;
-               other._size = 0;
-               other._head = 0;
-               other._tail = 0;
-       }
-
-       
-       CircularBuffer& operator=(CircularBuffer&& other) noexcept{
-               if ( this != &other){
-                       _buff = std::move(other._buff);
-                       _max_size = other._max_size;
-                       _size = other._size;
-                       _head = other._head;
-                       _tail = other._tail;
-                       
-                       other._buff = nullptr;
-                       other._max_size = 0;
-                       other._size = 0;
-                       other._head = 0;
-                       other._tail = 0;                        
-               }
-               return *this;
-       }
-       
-       void push_back(const value_type& data);
-       void push_back(value_type&& data) noexcept;
-       void pop_front();
-       reference front();
-       reference back(); 
-       const_reference front() const; 
-       const_reference back() const;
-       void clear();
-       bool empty() const ;
-       bool full() const ;
-       size_type capacity() const ;
-       size_type size() const;
-       size_type buffer_size() const {return sizeof(value_type)*_max_size;};
-       const_pointer data() const { return _buff.get(); }
-       
-       const_reference operator[](size_type index) const;
-       reference operator[](size_type index);
-       const_reference at(size_type index) const;
-       reference at(size_type index);
-
-       typedef BufferIterator<false> iterator;
-       typedef BufferIterator<true> const_iterator;
-       
-       iterator begin();
-       const_iterator begin() const;
-       iterator end();
-       const_iterator end() const;
-       const_iterator cbegin() const noexcept;
-       const_iterator cend() const noexcept;
-       iterator rbegin() noexcept;
-       const_iterator rbegin() const noexcept;
-       iterator rend() noexcept;
-       const_iterator rend() const noexcept;
-       
-               
-private:
-       void _increment_bufferstate();
-       void _decrement_bufferstate();
-    // clyne
-       //mutable std::mutex _mtx;
-       std::unique_ptr<value_type[]> _buff;
-       size_type _head = 0;
-       size_type _tail = 0;
-       size_type _size = 0;
-       size_type _max_size = 0;
-                       
-    template<bool isConst = false>
-       struct  BufferIterator{
-       public:
-               friend class CircularBuffer<T>;
-               typedef std::random_access_iterator_tag iterator_category;
-               typedef ptrdiff_t difference_type;
-               typedef T value_type;
-               typedef typename std::conditional<isConst, const value_type&, value_type&>::type reference;
-               typedef typename std::conditional<isConst, const value_type*, value_type*>::type pointer;
-               typedef typename std::conditional<isConst, const CircularBuffer<value_type>*,
-                                                                                 CircularBuffer<value_type>*>::type cbuf_pointer;
-       private:
-               cbuf_pointer _ptrToBuffer;
-               size_type _offset;
-               size_type _index;
-               bool _reverse;
-               
-               bool _comparable(const BufferIterator<isConst>& other) const{
-                       return (_ptrToBuffer == other._ptrToBuffer)&&(_reverse == other._reverse);
-               }
-               
-       public:
-               BufferIterator()
-                       :_ptrToBuffer{nullptr}, _offset{0}, _index{0}, _reverse{false}{}
-               
-               BufferIterator(const BufferIterator<false>& it)
-                       :_ptrToBuffer{it._ptrToBuffer},
-                        _offset{it._offset},
-                        _index{it._index},
-                        _reverse{it._reverse}{}
-
-               reference operator*(){
-                       if(_reverse)
-                               return (*_ptrToBuffer)[(_ptrToBuffer->size() - _index - 1)];
-                       return (*_ptrToBuffer)[_index];
-               }
-
-               pointer  operator->() { return &(operator*()); }
-
-               reference operator[](size_type index){
-                       BufferIterator iter = *this;
-                       iter._index += index;
-                       return *iter;
-               }
-
-               BufferIterator& operator++(){
-                       ++_index;
-                       return *this;
-               }
-
-               BufferIterator operator++(int){
-                       BufferIterator iter = *this;
-                       ++_index;
-                       return iter;
-               }
-
-               BufferIterator& operator--(){
-                       --_index;
-                       return *this;
-               }
-
-               BufferIterator operator--(int){
-                       BufferIterator iter = *this;
-                       --_index;
-                       return iter;
-               }       
-
-               friend BufferIterator operator+(BufferIterator lhsiter, difference_type n){
-                       lhsiter._index += n;
-                       return lhsiter;
-               }
-
-               friend BufferIterator operator+(difference_type n, BufferIterator rhsiter){
-                       rhsiter._index += n;
-                       return rhsiter;
-               }
-               
-
-               BufferIterator& operator+=(difference_type n){
-                       _index += n;
-                       return *this;
-               }
-
-               friend BufferIterator operator-(BufferIterator lhsiter, difference_type n){
-                       lhsiter._index -= n;
-                       return lhsiter;
-               }
-
-               friend difference_type operator-(const BufferIterator& lhsiter, const BufferIterator& rhsiter){
-                       
-                       return lhsiter._index - rhsiter._index;
-               }
-
-               BufferIterator& operator-=(difference_type n){
-                       _index -= n;
-                       return *this;
-               }
-
-               bool operator==(const BufferIterator& other) const{
-                       if (!_comparable(other))
-                               return false;
-                       return ((_index == other._index)&&(_offset == other._offset));
-               }
-               
-               bool operator!=(const BufferIterator& other) const{
-                       if (!_comparable(other))
-                               return true;
-                       return ((_index != other._index)||(_offset != other._offset));
-               }
-
-               bool operator<(const BufferIterator& other) const {
-                       if (!_comparable(other))
-                               return false;
-                       return ((_index + _offset)<(other._index+other._offset));
-               }
-
-               bool operator>(const BufferIterator& other) const{
-                       if (!_comparable(other))
-                               return false;
-                       return ((_index + _offset)>(other._index+other._offset));
-               }
-
-               bool operator<=(const BufferIterator& other) const {
-                       if (!_comparable(other))
-                               return false;
-                       return ((_index + _offset)<=(other._index+other._offset));
-               }
-
-               bool operator>=(const BufferIterator& other) const {
-                       if (!_comparable(other))
-                               return false;
-                       return ((_index + _offset)>=(other._index+other._offset));
-               }
-       };
-};
-
-template<typename T>
-inline 
-bool CircularBuffer<T>::full() const{
-       return _size == _max_size;
-}
-
-template<typename T>
-inline 
-bool CircularBuffer<T>::empty() const{
-       return _size == 0;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::size_type CircularBuffer<T>::capacity() const{
-       return _max_size;
-}
-
-template<typename T>
-inline 
-void  CircularBuffer<T>::clear(){
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       _head = _tail = _size = 0;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::size_type CircularBuffer<T>::size() const{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       return _size;
-       }
-
-template<typename T>
-inline
-typename CircularBuffer<T>::reference CircularBuffer<T>::front() {
-       //std::lock_guard<std::mutex> _lck(_mtx);
-    // clyne
-       if(empty())
-               abort(); //throw std::length_error("front function called on empty buffer");
-       return _buff[_tail];
-}
-
-template<typename T>
-inline
-typename CircularBuffer<T>::reference CircularBuffer<T>::back() {
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       if(empty())
-               abort(); //throw std::length_error("back function called on empty buffer");
-       return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1];
-}
-
-template<typename T>
-inline
-typename CircularBuffer<T>::const_reference CircularBuffer<T>::front() const{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       if(empty())
-               abort(); //throw std::length_error("front function called on empty buffer");
-       return _buff[_tail];
-}
-
-template<typename T>
-inline
-typename CircularBuffer<T>::const_reference CircularBuffer<T>::back() const{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       if(empty())
-               abort(); //throw std::length_error("back function called on empty buffer");
-       return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1];
-}
-
-template<typename T>
-inline
-void CircularBuffer<T>::push_back(const T& data){
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       //if(full())
-       //      _buff[_tail].~T();
-       _buff[_head] = data;
-       _increment_bufferstate();
-}
-
-template<typename T>
-inline
-void CircularBuffer<T>::push_back(T&& data) noexcept{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       _buff[_head] = std::move(data);
-       _increment_bufferstate();
-}
-
-
-template<typename T>
-inline 
-void CircularBuffer<T>::_increment_bufferstate(){
-       if(full())
-               _tail = (_tail + 1)%_max_size;
-       else
-               ++_size;
-       _head = (_head + 1)%_max_size;  
-}
-
-template<typename T>
-inline 
-void CircularBuffer<T>::pop_front(){
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       if(empty())
-               abort(); //throw std::length_error("pop_front called on empty buffer");
-       _decrement_bufferstate();
-}
-
-template<typename T>
-inline 
-void CircularBuffer<T>::_decrement_bufferstate(){
-       --_size;
-       _tail = (_tail + 1)%_max_size;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::reference CircularBuffer<T>::operator[](size_t index) {
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       if((index<0)||(index>=_size))
-               abort(); //throw std::out_of_range("Index is out of Range of buffer size");
-       index += _tail;
-       index %= _max_size;
-       return _buff[index];
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::const_reference CircularBuffer<T>::operator[](size_t index) const {
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       if((index<0)||(index>=_size))
-               abort(); //throw std::out_of_range("Index is out of Range of buffer size");
-       index += _tail;
-       index %= _max_size;
-       return _buff[index];
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::reference CircularBuffer<T>::at(size_t index) {
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       if((index<0)||(index>=_size))
-               abort(); //throw std::out_of_range("Index is out of Range of buffer size");
-       index += _tail;
-       index %= _max_size;
-       return _buff[index];
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::const_reference CircularBuffer<T>::at(size_t index) const {
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       if((index<0)||(index>=_size))
-               abort(); //throw std::out_of_range("Index is out of Range of buffer size");
-       index += _tail;
-       index %= _max_size;
-       return _buff[index];
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::iterator CircularBuffer<T>::begin() {
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = 0;
-       iter._reverse = false;
-       return iter;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::const_iterator CircularBuffer<T>::begin() const{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       const_iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = 0;
-       iter._reverse = false;
-       return iter;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::iterator CircularBuffer<T>::end() {
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = _size;
-       iter._reverse = false;
-       return iter;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::const_iterator CircularBuffer<T>::end() const{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       const_iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = _size;
-       iter._reverse = false;
-       return iter;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::const_iterator CircularBuffer<T>::cbegin() const noexcept{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       const_iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = 0;
-       iter._reverse = false;
-       return iter;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::const_iterator CircularBuffer<T>::cend() const noexcept{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       const_iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = _size;
-       iter._reverse = false;
-       return iter;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::iterator CircularBuffer<T>::rbegin() noexcept{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = 0;
-       iter._reverse = true;
-       return iter;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::const_iterator CircularBuffer<T>::rbegin() const noexcept{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       const_iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = 0;
-       iter._reverse = true;
-       return iter;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::iterator CircularBuffer<T>::rend()  noexcept{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = _size;
-       iter._reverse = true;
-       return iter;
-}
-
-template<typename T>
-inline 
-typename CircularBuffer<T>::const_iterator CircularBuffer<T>::rend() const noexcept{
-       //std::lock_guard<std::mutex> _lck(_mtx);
-       const_iterator iter;
-       iter._ptrToBuffer = this;
-       iter._offset = _tail;
-       iter._index = _size;
-       iter._reverse = true;
-       return iter;
-}
-
-#endif /* CIRCULAR_BUFFER_H */
diff --git a/gdt.cpp b/gdt.cpp
deleted file mode 100644 (file)
index 24d974b..0000000
--- a/gdt.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-#include <array>
-#include <cstdint>
-
-struct gdt_entry_bits {
-    std::uint32_t limit_low              : 16;
-    std::uint32_t base_low               : 24;
-    std::uint32_t accessed               :  1;
-    std::uint32_t read_write             :  1; // readable for code, writable for data
-    std::uint32_t conforming_expand_down :  1; // conforming for code, expand down for data
-    std::uint32_t code                   :  1; // 1 for code, 0 for data
-    std::uint32_t code_data_segment      :  1; // should be 1 for everything but TSS and LDT
-    std::uint32_t DPL                    :  2; // privilege level
-    std::uint32_t present                :  1;
-    std::uint32_t limit_high             :  4;
-    std::uint32_t available              :  1; // only used in software; has no effect on hardware
-    std::uint32_t long_mode              :  1;
-    std::uint32_t big                    :  1; // 32-bit opcodes for code, uint32_t stack for data
-    std::uint32_t gran                   :  1; // 1 to use 4k page addressing, 0 for byte addressing
-    std::uint32_t base_high              :  8;
-} __attribute__((packed));
-
-struct TSSEntry
-{
-    std::uint32_t prevTSS;
-    std::uint32_t esp0;
-    std::uint32_t ss0;
-    std::uint32_t unused[23] = {};
-} __attribute__((packed));
-
-static TSSEntry tss = {
-    .prevTSS = 0,
-    .esp0 = 0,
-    .ss0 = 0x10
-};
-
-static const std::array<gdt_entry_bits, 6> gdt {{
-    {},
-    /* kernel_code = */ {
-        .limit_low = 0xFFFF,
-        .base_low = 0x0000,
-        .accessed = 0,
-        .read_write = 1,
-        .conforming_expand_down = 0,
-        .code = 1,
-        .code_data_segment = 1,
-        .DPL = 0,
-        .present = 1,
-        .limit_high = 0xF,
-        .available = 0,
-        .long_mode = 0,
-        .big = 1,
-        .gran = 1,
-        .base_high = 0x00
-    },
-    /* kernel_data = */ {
-        .limit_low = 0xFFFF,
-        .base_low = 0x0000,
-        .accessed = 0,
-        .read_write = 1,
-        .conforming_expand_down = 0,
-        .code = 0,
-        .code_data_segment = 1,
-        .DPL = 0,
-        .present = 1,
-        .limit_high = 0xF,
-        .available = 0,
-        .long_mode = 0,
-        .big = 1,
-        .gran = 1,
-        .base_high = 0x00
-    },
-    /* user_code = */ {
-        .limit_low = 0xFFFF,
-        .base_low = 0x0000,
-        .accessed = 0,
-        .read_write = 1,
-        .conforming_expand_down = 0,
-        .code = 1,
-        .code_data_segment = 1,
-        .DPL = 3,
-        .present = 1,
-        .limit_high = 0xF,
-        .available = 0,
-        .long_mode = 0,
-        .big = 1,
-        .gran = 1,
-        .base_high = 0x00
-    },
-    /* user_data = */ {
-        .limit_low = 0xFFFF,
-        .base_low = 0x0000,
-        .accessed = 0,
-        .read_write = 1,
-        .conforming_expand_down = 0,
-        .code = 0,
-        .code_data_segment = 1,
-        .DPL = 3,
-        .present = 1,
-        .limit_high = 0xF,
-        .available = 0,
-        .long_mode = 0,
-        .big = 1,
-        .gran = 1,
-        .base_high = 0x00
-    },
-    /* tss = */ {
-        .limit_low = sizeof(TSSEntry),
-        .base_low = (std::uint32_t)&tss & 0xFFFFFF,
-        .accessed = 1,
-        .read_write = 0,
-        .conforming_expand_down = 0,
-        .code = 1,
-        .code_data_segment = 0,
-        .DPL = 0,
-        .present = 1,
-        .limit_high = 0,
-        .available = 0,
-        .long_mode = 0,
-        .big = 0,
-        .gran = 0,
-        .base_high = (std::uint32_t)&tss >> 24
-    }
-}};
-
-void gdt_initialize()
-{
-    auto gdtr = reinterpret_cast<std::uint64_t>(gdt.data());
-    gdtr <<= 16;
-    gdtr |= gdt.size() * sizeof(gdt[0]);
-
-    asm volatile(R"(
-        lgdt %0
-        pushl $0x8
-        push $.setcs
-        ljmp *(%%esp)
-    .setcs:
-        add $8, %%esp
-        mov $0x10, %%eax
-        mov %%eax, %%ds
-        mov %%eax, %%es
-        mov %%eax, %%fs
-        mov %%eax, %%gs
-        mov %%eax, %%ss
-
-        mov $0x28, %%ax
-        ltr %%ax
-    )" :: "m"(gdtr));
-}
-
-void enter_user_mode(void (*func)())
-{
-    asm volatile("mov %%esp, %0" : "=r" (tss.esp0));
-
-    asm volatile(R"(
-        mov $0x23, %%ax
-        mov %%ax, %%ds
-        mov %%ax, %%es
-        mov %%ax, %%fs
-        mov %%ax, %%gs
-        mov %%esp, %%eax
-        push $0x23
-        push %%esp
-        pushf
-        push $0x1b
-        push %0
-        iret
-    )" :: "b"(func));
-}
-
diff --git a/gdt.hpp b/gdt.hpp
deleted file mode 100644 (file)
index de5e8fc..0000000
--- a/gdt.hpp
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef GDT_HPP
-#define GDT_HPP
-
-void gdt_initialize();
-void enter_user_mode(void (*func)());
-
-#endif // GDT_HPP
-
diff --git a/idt.cpp b/idt.cpp
deleted file mode 100644 (file)
index 5380c9e..0000000
--- a/idt.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-#include "idt.hpp"
-#include "portio.hpp"
-#include "textoutput.hpp"
-
-#include <array>
-#include <cstdint>
-#include <utility>
-
-extern TextOutput& term;
-
-static constexpr unsigned InterruptCount = 49;
-
-static constexpr std::uint8_t TaskGate   = 0x5;
-static constexpr std::uint8_t IntrGate16 = 0x6;
-static constexpr std::uint8_t TrapGate16 = 0x7;
-static constexpr std::uint8_t IntrGate32 = 0xE;
-static constexpr std::uint8_t TrapGate32 = 0xF;
-
-struct idt_entry_bits {
-    std::uint32_t offset_low             : 16;
-    std::uint32_t segment_selector       : 16;
-    std::uint32_t rsvd                   :  8 = 0;
-    std::uint32_t gate_type              :  4;
-    std::uint32_t rsvd2                  :  1 = 0;
-    std::uint32_t dpl                    :  2;
-    std::uint32_t present                :  1;
-    std::uint32_t offset_high            : 16;
-} __attribute__((packed));
-
-static std::array<Callback, InterruptCount> callbacks;
-
-extern "C"
-void interruptGeneralHandler(Registers regs)
-{
-    const auto& inum = regs.inum;
-
-    if (inum >= 32) {
-        if (inum >= 40)
-            outb(0xA0, 0x20);
-
-        outb(0x20, 0x20);
-    }
-
-    if (inum < callbacks.size()) {
-        if (auto cb = callbacks[inum]; cb) {
-            asm volatile("cli");
-            cb(regs);
-            asm volatile("sti");
-        }
-    }
-}
-
-template<std::size_t N>
-struct StubEntry
-{
-    static constexpr bool HasError = N == 8 || (N >= 10 && N <= 14) || N == 17 || N == 30;
-
-    __attribute__((naked))
-    static void stub() {
-        if constexpr (!HasError)
-            asm volatile("push $0x0");
-
-        asm volatile(R"(
-            pusha
-            mov %%ds, %%eax
-            push %%eax
-            mov $0x10, %%ax
-            mov %%ax, %%ds
-            mov %%ax, %%es
-            mov %%ax, %%fs
-            mov %%ax, %%gs
-            push %0
-            cld
-            call interruptGeneralHandler
-            pop %%eax
-            pop %%eax
-            mov %%ax, %%ds
-            mov %%ax, %%es
-            mov %%ax, %%fs
-            mov %%ax, %%gs
-            popa
-            add $0x4, %%esp
-            iret
-        )" :: "i"(N));
-    }
-
-    static constexpr std::uint32_t segment(std::uint16_t gdt_idx, bool useLdt, std::uint16_t rpl) {
-        return gdt_idx | (useLdt ? 0x4 : 0x0) | (rpl & 0x3);
-    }
-
-    idt_entry_bits entry = {
-        .offset_low = (uint32_t)stub & 0xFFFF,
-        .segment_selector = segment(0x8, false, 0),
-        .gate_type = IntrGate32,
-        .dpl = 0,
-        .present = 1,
-        .offset_high = (uint32_t)stub >> 16
-    };
-
-    operator idt_entry_bits() const noexcept {
-        return entry;
-    }
-};
-
-static auto idt =
-    []<std::size_t... ints>(std::index_sequence<ints...>) {
-        return std::array<idt_entry_bits, 256> { StubEntry<ints>()... };
-    }(std::make_index_sequence<InterruptCount>{});
-
-void idt_initialize()
-{
-    idt[0x28].dpl = 3;
-
-    auto idtr = reinterpret_cast<std::uint64_t>(idt.data());
-    idtr <<= 16;
-    idtr |= idt.size() * sizeof(idt[0]);
-
-    asm volatile("lidt %0" :: "m"(idtr));
-}
-
-void idt_register_callback(std::size_t num, Callback cb)
-{
-    if (num < callbacks.size())
-        callbacks[num] = cb;
-}
-
diff --git a/idt.hpp b/idt.hpp
deleted file mode 100644 (file)
index c5e7e47..0000000
--- a/idt.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef IDT_HPP
-#define IDT_HPP
-
-#include <cstddef>
-#include <cstdint>
-
-struct Registers
-{
-    std::uint32_t inum;
-    std::uint32_t ds;
-    std::uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
-    std::uint32_t error;
-    std::uint32_t eip, cs, eflags;
-} __attribute__((packed));
-
-using Callback = void (*)(const Registers&);
-
-void idt_initialize();
-void idt_register_callback(std::size_t num, Callback cb);
-
-#endif // IDT_HPP
-
diff --git a/kernel.cpp b/kernel.cpp
deleted file mode 100644 (file)
index ae3f153..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-#include "acpi.hpp"
-#include "ata.hpp"
-#include "gdt.hpp"
-#include "idt.hpp"
-#include "keyboard.hpp"
-#include "memory.hpp"
-#include "multiboot.hpp"
-#include "pic.hpp"
-#include "pit.hpp"
-#include "portio.hpp"
-#include "tasking.hpp"
-#include "vgaterminal.hpp"
-
-static VGATerminal vga;
-TextOutput& term = vga;
-
-static volatile bool termBusy = false;
-
-void ata_probe(auto bus, ATA::Drive drv, const char *name)
-{
-    switch (bus.identify(drv)) {
-    case ATA::Type::ATA:
-        term.write("ata:");
-        term.write(name);
-        term.write(": ATA drive detected.\n");
-        break;
-    case ATA::Type::ATAPI:
-        term.write("ata:");
-        term.write(name);
-        term.write(": ATAPI drive detected.\n");
-        break;
-    default:
-        break;
-    }
-}
-
-void kernel_main(void) 
-{
-    term.write("Clyne's kernel, v2024\n\n");
-
-    if (!multiboot_initialize())
-        for (;;);
-
-    idt_register_callback(14, [](auto& regs) {
-        term.write("Page fault! eip=");
-        term.write(regs.eip);
-        term.write('\n');
-        for (;;);
-    });
-
-    acpi_initialize();
-    memory_initialize();
-    gdt_initialize();
-    pic_initialize();
-    idt_initialize();
-    pit_initialize();
-    keyboard_initialize();
-    asm volatile("sti");
-    tasking_initialize();
-    term.write("Tasking enabled.\n");
-
-    ATA::Bus<ATA::Primary> bus0;
-    ATA::Bus<ATA::Secondary> bus1;
-
-    ata_probe(bus0, ATA::Master, "0:0");
-    ata_probe(bus0, ATA::Slave,  "0:1");
-    ata_probe(bus1, ATA::Master, "1:0");
-    ata_probe(bus1, ATA::Slave,  "1:1");
-
-    idt_register_callback(0x28, [](auto& regs) {
-        term.write(static_cast<char>(regs.eax));
-    });
-
-    term.write("Entering user mode...\n");
-    enter_user_mode([] {
-        asm volatile("int $0x28" :: "a" ('Z'));
-        for (;;);
-    });
-
-    for (;;) {
-        const auto ch = keyboard_read();
-        if (ch)
-            term.write(*ch);
-
-        pit_delay_ms(10);
-    }
-}
-
-extern "C"
-void abort()
-{
-    term.write("!!! abort() called !!!");
-    asm volatile("cli");
-    for (;;);
-}
-
-extern "C"
-int __cxa_atexit(void (*)(void *), void *, void *)
-{
-    return 0;
-}
-
-int __dso_handle = 0;
-
diff --git a/keyboard.cpp b/keyboard.cpp
deleted file mode 100644 (file)
index 48dad02..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-#include "circularbuffer.hpp"
-#include "idt.hpp"
-#include "keyboard.hpp"
-#include "portio.hpp"
-#include "vgaterminal.hpp"
-
-#include <array>
-#include <cstdint>
-
-extern TextOutput& term;
-
-static CircularBuffer<char> keyboardBuffer;
-static Port<0x60> keyboardPort;
-
-static const std::array<char, 0x59> ScanCodeSet1 {{
-    0, K_ESCAPE,
-    '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
-    '-', '=', '\b', '\t',
-    'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', '\n', K_CONTROL_L,
-    'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`', K_SHIFT_L, '\\',
-    'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/',
-    K_SHIFT_R, '*', K_ALT_L, ' ', K_CAPS,
-    K_F1, K_F2, K_F3, K_F4, K_F5, K_F6, K_F7, K_F8, K_F9, K_F10,
-    K_NUM, K_SCROLL, '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.',
-    0, 0, 0, // non-existant
-    K_F11, K_F12
-}};
-
-static inline bool isReleased(auto ch) {
-    return ch & 0x80;
-}
-
-static inline auto keycode(auto ch) {
-    return ch & 0x7F;
-}
-
-void keyboard_initialize()
-{
-    keyboardBuffer = CircularBuffer<char>(128);
-
-    idt_register_callback(33, [](auto&) {
-        const std::uint8_t kc = keyboardPort;
-
-        if (!isReleased(kc)) {
-            const auto ch = ScanCodeSet1[keycode(kc)];
-            //if (ch > 0)
-            //    term.write(ch);
-
-            keyboardBuffer.push_back(ch);
-        }
-    });
-}
-
-std::optional<char> keyboard_read()
-{
-    if (keyboardBuffer.empty()) {
-        return {};
-    } else {
-        const auto ch = keyboardBuffer.front();
-        keyboardBuffer.pop_front();
-        return ch;
-    }
-}
-
diff --git a/keyboard.hpp b/keyboard.hpp
deleted file mode 100644 (file)
index 694ff89..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef KEYBOARD_HPP
-#define KEYBOARD_HPP
-
-#include <optional>
-
-#define K_CONTROL_L -1
-#define K_SHIFT_L   -2
-#define K_ALT_L     -3
-#define K_CAPS      -4
-#define K_NUM       -5
-#define K_SCROLL    -6
-#define K_SHIFT_R   -7
-#define K_ESCAPE    -8
-#define K_F1        -10
-#define K_F2        -11
-#define K_F3        -12
-#define K_F4        -13
-#define K_F5        -14
-#define K_F6        -15
-#define K_F7        -16
-#define K_F8        -17
-#define K_F9        -18
-#define K_F10       -19
-#define K_F11       -20
-#define K_F12       -21
-
-void keyboard_initialize();
-
-std::optional<char> keyboard_read();
-
-#endif // KEYBOARD_HPP
-
diff --git a/memmove.cpp b/memmove.cpp
deleted file mode 100644 (file)
index 06e37df..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Taken from newlib... */
-
-#include <cstring>
-#include <cstddef>
-#include <climits>
-
-/* Nonzero if either X or Y is not aligned on a "long" boundary.  */
-#define UNALIGNED(X, Y) \
-  (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
-
-/* How many bytes are copied each iteration of the 4X unrolled loop.  */
-#define BIGBLOCKSIZE    (sizeof (long) << 2)
-
-/* How many bytes are copied each iteration of the word copy loop.  */
-#define LITTLEBLOCKSIZE (sizeof (long))
-
-/* Threshhold for punting to the byte copier.  */
-#define TOO_SMALL(LEN)  ((LEN) < BIGBLOCKSIZE)
-
-extern "C"
-void *memmove (void *dst_void, const void *src_void, size_t length)
-{
-  char *dst = reinterpret_cast<char *>(dst_void);
-  const char *src = reinterpret_cast<const char *>(src_void);
-  long *aligned_dst;
-  const long *aligned_src;
-
-  if (src < dst && dst < src + length)
-    {
-      /* Destructive overlap...have to copy backwards */
-      src += length;
-      dst += length;
-      while (length--)
-       {
-         *--dst = *--src;
-       }
-    }
-  else
-    {
-      /* Use optimizing algorithm for a non-destructive copy to closely 
-         match memcpy. If the size is small or either SRC or DST is unaligned,
-         then punt into the byte copy loop.  This should be rare.  */
-      if (!TOO_SMALL(length) && !UNALIGNED (src, dst))
-        {
-          aligned_dst = (long*)dst;
-          aligned_src = (long*)src;
-
-          /* Copy 4X long words at a time if possible.  */
-          while (length >= BIGBLOCKSIZE)
-            {
-              *aligned_dst++ = *aligned_src++;
-              *aligned_dst++ = *aligned_src++;
-              *aligned_dst++ = *aligned_src++;
-              *aligned_dst++ = *aligned_src++;
-              length -= BIGBLOCKSIZE;
-            }
-
-          /* Copy one long word at a time if possible.  */
-          while (length >= LITTLEBLOCKSIZE)
-            {
-              *aligned_dst++ = *aligned_src++;
-              length -= LITTLEBLOCKSIZE;
-            }
-
-          /* Pick up any residual with a byte copier.  */
-          dst = (char*)aligned_dst;
-          src = (char*)aligned_src;
-        }
-
-      while (length--)
-        {
-          *dst++ = *src++;
-        }
-    }
-
-  return dst_void;
-}
-
diff --git a/memory.cpp b/memory.cpp
deleted file mode 100644 (file)
index 108c240..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-#include "textoutput.hpp"
-
-#include <array>
-#include <cstdint>
-
-struct PageDirectory
-{
-    static constexpr std::uint32_t NotPresent = 0x2;
-
-    PageDirectory(): value(NotPresent) {}
-    PageDirectory(void *addr): value(reinterpret_cast<std::uint32_t>(addr) | 7) {}
-
-    std::uint32_t value;
-};
-static_assert(sizeof(PageDirectory) == sizeof(std::uint32_t));
-
-extern std::uint32_t lowerMem;
-extern std::uint32_t upperMem;
-extern TextOutput& term;
-
-static std::uintptr_t lowerFree = 0x400;
-static std::uintptr_t upperFree = 0x100000;
-
-alignas(4096)
-static std::array<PageDirectory, 1024> pageDirectory;
-
-alignas(4096)
-static std::array<std::uint32_t, 1024> pageTable;
-
-void memory_initialize()
-{
-    lowerMem -= 1024;
-
-    const auto totalKb = (lowerMem + upperMem) / 1024u;
-
-    term.write("Claiming ");
-    term.write(totalKb);
-    term.write(" kB for allocations...\n");
-
-    std::uint32_t addr = 0;
-    for (auto& p : pageTable) {
-        p = addr | 7; // supervisor, r/w, present
-        addr += 0x1000;
-    }
-
-    pageDirectory[0] = PageDirectory(pageTable.data());
-
-    asm volatile(R"(
-        mov %%eax, %%cr3
-        mov %%cr0, %%eax
-        or $0x80000000, %%eax
-        mov %%eax, %%cr0
-    )" :: "a"(pageDirectory.data()));
-
-    term.write("Paging enabled.\n");
-}
-
-static void *memory_alloc(std::size_t size)
-{
-    void *ret = nullptr;
-
-    if (lowerMem > size) {
-        ret = reinterpret_cast<void *>(lowerFree);
-        lowerFree += size;
-        lowerMem -= size;
-    } else if (upperMem > size) {
-        ret = reinterpret_cast<void *>(upperFree);
-        upperFree += size;
-        upperMem -= size;
-    } else {
-        // Uh oh!
-        term.write("!!! Kernel allocation failed !!!");
-    }
-
-    return ret;
-}
-
-void *operator new(std::size_t size)
-{
-    return memory_alloc(size);
-}
-
-void *operator new[](std::size_t size)
-{
-    return memory_alloc(size);
-}
-
-void operator delete(void *)
-{
-
-}
-
-void operator delete[](void *)
-{
-
-}
-
-void operator delete(void *, std::size_t)
-{
-
-}
-
-void operator delete[](void *, std::size_t)
-{
-
-}
-
diff --git a/memory.hpp b/memory.hpp
deleted file mode 100644 (file)
index 0467bf6..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef MEMORY_HPP
-#define MEMORY_HPP
-
-#include <cstddef>
-#include <type_traits>
-
-template<typename T>
-struct kallocator
-{
-    using value_type = T;
-    using size_type = std::size_t;
-    using difference_type = std::ptrdiff_t;
-    using propagate_on_container_move_assignment = std::true_type;
-    using is_always_equal = std::true_type;
-
-    template<class U>
-    struct rebind {
-        typedef kallocator<U> other;
-    };
-
-    kallocator() = default;
-
-    template<typename U>
-    kallocator(const kallocator<U>&) noexcept {}
-
-    T* allocate(std::size_t n) {
-        return new T[n];
-    }
-
-    void deallocate([[maybe_unused]] T* p, [[maybe_unused]] std::size_t n) {
-
-    }
-};
-
-void memory_initialize();
-
-#endif // MEMORY_HPP
-
diff --git a/multiboot.cpp b/multiboot.cpp
deleted file mode 100644 (file)
index 46c505b..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-#include "textoutput.hpp"
-
-#include <cstdint>
-
-extern TextOutput& term;
-
-struct multiboot2_tag
-{
-    alignas(8)
-    std::uint16_t id;
-    std::uint16_t flags;
-    std::uint32_t length;
-    std::uint32_t data[1];
-} __attribute__((packed));
-
-template<int N>
-struct multiboot2
-{
-    static constexpr std::uint32_t MAGIC    = 0xE85250D6;
-    static constexpr std::uint32_t FLAGS    = 0;
-    static constexpr std::uint32_t LENGTH   = 16;
-    static constexpr std::uint32_t CHECKSUM = -(MAGIC + FLAGS + LENGTH);
-
-    alignas(8)
-    std::uint32_t magic = MAGIC;
-    std::uint32_t flags = FLAGS;
-    std::uint32_t length = LENGTH;
-    std::uint32_t checksum = CHECKSUM;
-
-    multiboot2_tag tags[N];
-} __attribute__((packed));
-
-__attribute__((section(".multiboot2")))
-multiboot2 multibootHeader = {
-    .tags = {
-        {
-            1, 0, sizeof(multiboot2_tag) + sizeof(std::uint32_t),
-            {4}
-        },
-        {
-            0, 0, 8, {}
-        }
-    }
-};
-
-std::uint32_t multiboot_magic;
-std::uint32_t *multiboot_ptr;
-
-std::uint32_t lowerMem = 0;
-std::uint32_t upperMem = 0;
-std::uint32_t *acpiRsdp = nullptr;
-std::uint32_t *acpiRsdpV2 = nullptr;
-
-bool multiboot_initialize()
-{
-    if (multiboot_magic != 0x36d76289) {
-        term.write("Not multiboot!");
-        return false;
-    }
-
-    term.write("Found multiboot headers: ");
-
-    auto ptr = multiboot_ptr + 2;
-    while (ptr[0] != 0 && ptr[1] != 8) {
-        term.write(ptr[0]);
-        term.write(", ");
-
-        switch (ptr[0]) {
-        case 4:
-            lowerMem = ptr[2] * 1024;
-            upperMem = ptr[3] * 1024;
-            break;
-        case 14:
-            acpiRsdp = ptr + 2;
-            break;
-        case 15:
-            acpiRsdpV2 = ptr + 2;
-            break;
-        default:
-            break;
-        }
-    
-        auto next = reinterpret_cast<std::uintptr_t>(ptr);
-        next += ptr[1];
-        next = (next + 7) & ~7;
-        ptr = reinterpret_cast<std::uint32_t *>(next);
-    }
-
-    term.write('\n');
-    return true;
-}
-
diff --git a/multiboot.hpp b/multiboot.hpp
deleted file mode 100644 (file)
index 9916850..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef MULTIBOOT_HPP
-#define MULTIBOOT_HPP
-
-bool multiboot_initialize();
-
-#endif // MULTIBOOT_HPP
-
diff --git a/pic.cpp b/pic.cpp
deleted file mode 100644 (file)
index 437f384..0000000
--- a/pic.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "pic.hpp"
-
-#include "portio.hpp"
-
-#define PIC1           0x20            /* IO base address for master PIC */
-#define PIC2           0xA0            /* IO base address for slave PIC */
-#define PIC1_COMMAND   PIC1
-#define PIC1_DATA      (PIC1+1)
-#define PIC2_COMMAND   PIC2
-#define PIC2_DATA      (PIC2+1)
-
-#define PIC_EOI                0x20            /* End-of-interrupt command code */
-
-#define ICW1_ICW4    0x01              /* Indicates that ICW4 will be present */
-#define ICW1_SINGLE    0x02            /* Single (cascade) mode */
-#define ICW1_INTERVAL4    0x04         /* Call address interval 4 (8) */
-#define ICW1_LEVEL    0x08             /* Level triggered (edge) mode */
-#define ICW1_INIT    0x10              /* Initialization - required! */
-
-#define ICW4_8086    0x01              /* 8086/88 (MCS-80/85) mode */
-#define ICW4_AUTO    0x02              /* Auto (normal) EOI */
-#define ICW4_BUF_SLAVE    0x08         /* Buffered mode/slave */
-#define ICW4_BUF_MASTER    0x0C                /* Buffered mode/master */
-#define ICW4_SFNM    0x10              /* Special fully nested (not) */
-
-void pic_initialize()
-{
-    constexpr int offset1 = 0x20, offset2 = 0x28;
-    std::uint8_t a1, a2;
-    
-    a1 = inb(PIC1_DATA);                        // save masks
-    a2 = inb(PIC2_DATA);
-    
-    outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);  // starts the initialization sequence (in cascade mode)
-    io_wait();
-    outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
-    io_wait();
-    outb(PIC1_DATA, offset1);                 // ICW2: Master PIC vector offset
-    io_wait();
-    outb(PIC2_DATA, offset2);                 // ICW2: Slave PIC vector offset
-    io_wait();
-    outb(PIC1_DATA, 4);                      // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
-    io_wait();
-    outb(PIC2_DATA, 2);                       // ICW3: tell Slave PIC its cascade identity (0000 0010)
-    io_wait();
-    
-    outb(PIC1_DATA, ICW4_8086);               // ICW4: have the PICs use 8086 mode (and not 8080 mode)
-    io_wait();
-    outb(PIC2_DATA, ICW4_8086);
-    io_wait();
-    
-    outb(PIC1_DATA, a1);   // restore saved masks.
-    outb(PIC2_DATA, a2);
-}
-
-void pic_eoi(std::uint8_t irq)
-{
-    if (irq >= 8)
-        outb(PIC2_COMMAND, PIC_EOI);
-
-    outb(PIC1_COMMAND, PIC_EOI);
-}
-
diff --git a/pic.hpp b/pic.hpp
deleted file mode 100644 (file)
index 17abd55..0000000
--- a/pic.hpp
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef PIC_HPP
-#define PIC_HPP
-
-#include <cstdint>
-
-/* reinitialize the PIC controllers, giving them specified vector offsets
-   rather than 8h and 70h, as configured by default */
-void pic_initialize();
-void pic_eoi(std::uint8_t irq);
-
-#endif // PIC_HPP
-
diff --git a/pit.cpp b/pit.cpp
deleted file mode 100644 (file)
index 964522b..0000000
--- a/pit.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-#include "pit.hpp"
-#include "idt.hpp"
-#include "portio.hpp"
-#include "tasking.hpp"
-
-constexpr std::uint32_t Frequency = 1000;
-
-static volatile std::uint32_t ticks = 0;
-
-static void timer_callback(const Registers& regs)
-{
-    ticks = ticks + 1;
-
-    schedule(regs);
-}
-
-void pit_initialize()
-{
-   // Firstly, register our timer callback.
-   idt_register_callback(32, timer_callback);
-
-   // The value we send to the PIT is the value to divide it's input clock
-   // (1193180 Hz) by, to get our required frequency. Important to note is
-   // that the divisor must be small enough to fit into 16-bits.
-   const auto divisor = 1193180ul / Frequency;
-
-   // Send the command byte.
-   outb(0x43, 0x36);
-
-   // Send the frequency divisor.
-   outb(0x40, divisor & 0xFF);
-   outb(0x40, (divisor >> 8) & 0xFF);
-}
-
-void pit_delay_ms(std::int32_t ms)
-{
-    const auto end = ticks + ms;
-    while (static_cast<std::int32_t>(end - ticks) > 0)
-        asm volatile("nop");
-}
-
diff --git a/pit.hpp b/pit.hpp
deleted file mode 100644 (file)
index 55bcde9..0000000
--- a/pit.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef PIT_HPP
-#define PIT_HPP
-
-#include <cstdint>
-
-void pit_initialize();
-void pit_delay_ms(std::int32_t ms);
-
-#endif // PIT_HPP
-
diff --git a/portio.hpp b/portio.hpp
deleted file mode 100644 (file)
index 7636c14..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef PORTIO_HPP
-#define PORTIO_HPP
-
-#include <cstdint>
-
-inline void outb(std::uint16_t port, std::uint8_t val)
-{
-    asm volatile("out %%al, %%dx" :: "a"(val), "Nd"(port) : "memory");
-}
-
-inline std::uint8_t inb(std::uint16_t port)
-{
-    std::uint8_t val;
-    asm volatile("inb %%dx" : "=a"(val) : "Nd"(port) : "memory");
-    return val;
-}
-
-inline void outw(std::uint16_t port, std::uint16_t val)
-{
-    asm volatile("out %%ax, %%dx" :: "a"(val), "Nd"(port) : "memory");
-}
-
-inline std::uint16_t inw(std::uint16_t port)
-{
-    std::uint16_t val;
-    asm volatile("inw %%dx" : "=a"(val) : "Nd"(port) : "memory");
-    return val;
-}
-
-inline void io_wait()
-{
-    outb(0x80, 0);
-}
-
-template<std::uint16_t Addr>
-struct Port
-{
-    Port() = default;
-
-    template<typename T>
-    auto operator=(T val) noexcept {
-        if constexpr (sizeof(T) == 1)
-            outb(Addr, val);
-        else if constexpr (sizeof(T) == 2)
-            outw(Addr, val);
-
-        return *this;
-    }
-
-    template<typename T>
-    operator T() const noexcept {
-        if constexpr (sizeof(T) == 1)
-            return inb(Addr);
-        else if constexpr (sizeof(T) == 2)
-            return inw(Addr);
-    }
-
-    template<typename T>
-    bool operator==(T val) const noexcept {
-        T dat = *this;
-        return dat == val;
-    }
-
-    template<typename T>
-    auto operator&(T val) const noexcept {
-        T dat = *this;
-        return dat & val;
-    }
-};
-
-#endif // PORTIO_HPP
-
diff --git a/src/acpi.cpp b/src/acpi.cpp
new file mode 100644 (file)
index 0000000..b74a7dc
--- /dev/null
@@ -0,0 +1,51 @@
+#include "textoutput.hpp"
+
+#include <cstdint>
+
+extern TextOutput& term;
+extern std::uint32_t *acpiRsdp;
+extern std::uint32_t *acpiRsdpV2;
+
+struct XSDP {
+   char Signature[8];
+   std::uint8_t Checksum;
+   char OEMID[6];
+   std::uint8_t Revision;
+   std::uint32_t RsdtAddress;      // deprecated since version 2.0
+
+   // v2 only!
+   std::uint32_t Length;
+   std::uint64_t XsdtAddress;
+   std::uint8_t ExtendedChecksum;
+   std::uint8_t reserved[3];
+} __attribute__ ((packed));
+
+struct SDTHeader {
+    char Signature[4];
+    std::uint32_t Length;
+    std::uint8_t Revision;
+    std::uint8_t Checksum;
+    char OEMID[6];
+    char OEMTableID[8];
+    std::uint32_t OEMRevision;
+    std::uint32_t CreatorID;
+    std::uint32_t CreatorRevision;
+};
+
+static XSDP *rsdp = nullptr;
+
+void acpi_initialize()
+{
+    if (acpiRsdp) {
+        term.write("ACPI v1 detected.\n");
+        rsdp = reinterpret_cast<XSDP *>(acpiRsdp);
+    } else if (acpiRsdpV2) {
+        term.write("ACPI v2 detected, treating as v1.\n");
+        rsdp = reinterpret_cast<XSDP *>(acpiRsdpV2);
+    }
+
+    //if (rsdp) {
+    //    auto sdt = reinterpret_cast<SDTHeader *>(rsdp->RsdtAddress);
+    //}
+}
+
diff --git a/src/acpi.hpp b/src/acpi.hpp
new file mode 100644 (file)
index 0000000..8154b81
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef ACPI_HPP
+#define ACPI_HPP
+
+void acpi_initialize();
+
+#endif // ACPI_HPP
+
diff --git a/src/ata.cpp b/src/ata.cpp
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/ata.hpp b/src/ata.hpp
new file mode 100644 (file)
index 0000000..5394c31
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef ATA_HPP
+#define ATA_HPP
+
+#include "portio.hpp"
+
+#include <cstdint>
+#include <utility>
+
+namespace ATA
+{
+    enum class Type {
+        None,
+        ATA,
+        ATAPI
+    };
+
+    enum class Base : std::uint16_t {
+        Primary = 0x01F0,
+        Secondary = 0x0170
+    };
+
+    enum class Drive : std::uint8_t {
+        Master = 0xA0,
+        Slave = 0xB0
+    };
+
+    enum class Command : std::uint8_t {
+        Identify = 0xEC,
+        IdentifyPacketDevice = 0xA1
+    };
+
+    namespace Status {
+        static constexpr std::uint8_t Busy  = 0x80;
+        static constexpr std::uint8_t Ready = 0x40;
+        static constexpr std::uint8_t DF    = 0x20;
+        static constexpr std::uint8_t DSC   = 0x10;
+        static constexpr std::uint8_t DRQ   = 0x08;
+        static constexpr std::uint8_t CORR  = 0x04;
+        static constexpr std::uint8_t Index = 0x02;
+        static constexpr std::uint8_t Error = 0x01;
+    }
+
+    static constexpr std::uint8_t ATAPIIdentify0 = 0x14;
+    static constexpr std::uint8_t ATAPIIdentify1 = 0xEB;
+
+    using enum Base;
+    using enum Drive;
+
+    template<Base PBase>
+    struct Bus
+    {
+        template<Base b, unsigned offs>
+        using BPort = Port<std::to_underlying(b) + offs>;
+
+        [[no_unique_address]] BPort<PBase, 0> data;
+        [[no_unique_address]] BPort<PBase, 1> errFeats;
+        [[no_unique_address]] BPort<PBase, 2> count;
+        [[no_unique_address]] BPort<PBase, 3> lba0;
+        [[no_unique_address]] BPort<PBase, 4> lba1;
+        [[no_unique_address]] BPort<PBase, 5> lba2;
+        [[no_unique_address]] BPort<PBase, 6> select;
+        [[no_unique_address]] BPort<PBase, 7> cmdStat;
+
+        Type identify(Drive drv) {
+            auto type = Type::None;
+
+            data = std::to_underlying(drv);
+            count = '\0';
+            lba0 = '\0';
+            lba1 = '\0';
+            lba2 = '\0';
+            cmdStat = std::to_underlying(Command::Identify);
+    
+            if (cmdStat == '\0')
+                return type;
+
+            type = Type::ATA;
+            while (cmdStat & Status::Busy);
+
+            std::uint8_t stat;
+            do {
+                stat = cmdStat;
+
+                if (stat & Status::Error) {
+                    if (lba1 == ATAPIIdentify0 && lba2 == ATAPIIdentify1) {
+                        type = identifyAtapi(drv);
+                        break;
+                    } else {
+                        return type;
+                    }
+                }
+            } while (!(stat & Status::DRQ));
+
+            if (type != Type::None) {
+                for (int i = 0; i < 256; ++i) {
+                    volatile std::uint16_t w = data;
+                    (void)w;
+                }
+            }
+
+            return type;
+        }
+
+        Type identifyAtapi(Drive drv) {
+            data = std::to_underlying(drv);
+            count = '\0';
+            lba0 = '\0';
+            lba1 = '\0';
+            lba2 = '\0';
+            cmdStat = std::to_underlying(Command::IdentifyPacketDevice);
+    
+            if (cmdStat == '\0')
+                return Type::None;
+
+            while (cmdStat & Status::Busy);
+
+            std::uint8_t stat;
+            do {
+                stat = cmdStat;
+
+                if (stat & Status::Error)
+                    return Type::None;
+            } while (!(stat & Status::DRQ));
+
+            return Type::ATAPI;
+        }
+    };
+} // ATA
+
+#endif // ATA_HPP
+
diff --git a/src/boot.cpp b/src/boot.cpp
new file mode 100644 (file)
index 0000000..6b1da6a
--- /dev/null
@@ -0,0 +1,36 @@
+#include <array>
+#include <cstdint>
+#include <span>
+
+extern void (*__init_array_start)();
+extern void (*__init_array_end)();
+extern void kernel_main();
+
+alignas(16)
+static std::array<std::uint8_t, 16384> stack;
+
+static void init_array()
+{
+    std::span initArray (&__init_array_start, &__init_array_end);
+    for (auto& fn : initArray)
+        fn();
+}
+
+extern "C"
+__attribute__((naked))
+void _start()
+{
+    asm volatile(R"(
+        mov %%eax, multiboot_magic
+        mov %%ebx, multiboot_ptr
+        mov %0, %%esp
+    )" :: "i" (stack.data() + stack.size()));
+
+    init_array();
+    kernel_main();
+
+    asm volatile("cli");
+    for (;;)
+        asm volatile("hlt");
+}
+
diff --git a/src/circularbuffer.hpp b/src/circularbuffer.hpp
new file mode 100644 (file)
index 0000000..64a9e48
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+MIT License
+
+Copyright (c) 2020 Vinit James
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#ifndef CIRCULAR_BUFFER_H
+#define CIRCULAR_BUFFER_H
+
+#include <algorithm>
+#include <iterator>
+#include <mutex>
+#include <memory>
+#include <stdexcept>
+#include <utility>
+
+
+template<typename T>
+class CircularBuffer {
+private:
+       
+       typedef T* pointer;
+       typedef const T* const_pointer;
+       typedef T& reference;
+       typedef const T& const_reference;
+       typedef size_t size_type;
+       typedef ptrdiff_t difference_type;
+    template <bool isConst> struct BufferIterator;
+       
+
+public:
+    typedef T value_type;
+
+    // clyne
+    constexpr CircularBuffer()
+        :_buff{}, _max_size{0} {}
+
+       explicit CircularBuffer(size_t size)
+               :_buff{std::unique_ptr<T[]>(new value_type[size])}, _max_size{size}{}
+
+       CircularBuffer(const CircularBuffer& other)
+               :_buff{std::unique_ptr<T[]>(new value_type[other._max_size])},
+                _max_size{other._max_size},
+                _size{other._size},
+                _head{other._head},
+                _tail{other._tail}{
+                        std::copy(other.data(), other.data() + _max_size, _buff.get());
+                }
+
+       
+       CircularBuffer& operator=(const CircularBuffer& other){
+               if ( this != &other){
+                       _buff.reset(new value_type[other._max_size]);
+                       _max_size = other._max_size;
+                       _size = other._size;
+                       _head = other._head;
+                       _tail = other._tail;
+                       std::copy(other.data(), other.data() + _max_size, _buff.get());
+               }
+               return *this;
+       }
+
+       CircularBuffer(CircularBuffer&& other) noexcept
+               :_buff{std::move(other._buff)},
+                _max_size{other._max_size},
+                _size{other._size},
+                _head{other._head},
+                _tail{other._tail}{
+
+               other._buff = nullptr;
+               other._max_size = 0;
+               other._size = 0;
+               other._head = 0;
+               other._tail = 0;
+       }
+
+       
+       CircularBuffer& operator=(CircularBuffer&& other) noexcept{
+               if ( this != &other){
+                       _buff = std::move(other._buff);
+                       _max_size = other._max_size;
+                       _size = other._size;
+                       _head = other._head;
+                       _tail = other._tail;
+                       
+                       other._buff = nullptr;
+                       other._max_size = 0;
+                       other._size = 0;
+                       other._head = 0;
+                       other._tail = 0;                        
+               }
+               return *this;
+       }
+       
+       void push_back(const value_type& data);
+       void push_back(value_type&& data) noexcept;
+       void pop_front();
+       reference front();
+       reference back(); 
+       const_reference front() const; 
+       const_reference back() const;
+       void clear();
+       bool empty() const ;
+       bool full() const ;
+       size_type capacity() const ;
+       size_type size() const;
+       size_type buffer_size() const {return sizeof(value_type)*_max_size;};
+       const_pointer data() const { return _buff.get(); }
+       
+       const_reference operator[](size_type index) const;
+       reference operator[](size_type index);
+       const_reference at(size_type index) const;
+       reference at(size_type index);
+
+       typedef BufferIterator<false> iterator;
+       typedef BufferIterator<true> const_iterator;
+       
+       iterator begin();
+       const_iterator begin() const;
+       iterator end();
+       const_iterator end() const;
+       const_iterator cbegin() const noexcept;
+       const_iterator cend() const noexcept;
+       iterator rbegin() noexcept;
+       const_iterator rbegin() const noexcept;
+       iterator rend() noexcept;
+       const_iterator rend() const noexcept;
+       
+               
+private:
+       void _increment_bufferstate();
+       void _decrement_bufferstate();
+    // clyne
+       //mutable std::mutex _mtx;
+       std::unique_ptr<value_type[]> _buff;
+       size_type _head = 0;
+       size_type _tail = 0;
+       size_type _size = 0;
+       size_type _max_size = 0;
+                       
+    template<bool isConst = false>
+       struct  BufferIterator{
+       public:
+               friend class CircularBuffer<T>;
+               typedef std::random_access_iterator_tag iterator_category;
+               typedef ptrdiff_t difference_type;
+               typedef T value_type;
+               typedef typename std::conditional<isConst, const value_type&, value_type&>::type reference;
+               typedef typename std::conditional<isConst, const value_type*, value_type*>::type pointer;
+               typedef typename std::conditional<isConst, const CircularBuffer<value_type>*,
+                                                                                 CircularBuffer<value_type>*>::type cbuf_pointer;
+       private:
+               cbuf_pointer _ptrToBuffer;
+               size_type _offset;
+               size_type _index;
+               bool _reverse;
+               
+               bool _comparable(const BufferIterator<isConst>& other) const{
+                       return (_ptrToBuffer == other._ptrToBuffer)&&(_reverse == other._reverse);
+               }
+               
+       public:
+               BufferIterator()
+                       :_ptrToBuffer{nullptr}, _offset{0}, _index{0}, _reverse{false}{}
+               
+               BufferIterator(const BufferIterator<false>& it)
+                       :_ptrToBuffer{it._ptrToBuffer},
+                        _offset{it._offset},
+                        _index{it._index},
+                        _reverse{it._reverse}{}
+
+               reference operator*(){
+                       if(_reverse)
+                               return (*_ptrToBuffer)[(_ptrToBuffer->size() - _index - 1)];
+                       return (*_ptrToBuffer)[_index];
+               }
+
+               pointer  operator->() { return &(operator*()); }
+
+               reference operator[](size_type index){
+                       BufferIterator iter = *this;
+                       iter._index += index;
+                       return *iter;
+               }
+
+               BufferIterator& operator++(){
+                       ++_index;
+                       return *this;
+               }
+
+               BufferIterator operator++(int){
+                       BufferIterator iter = *this;
+                       ++_index;
+                       return iter;
+               }
+
+               BufferIterator& operator--(){
+                       --_index;
+                       return *this;
+               }
+
+               BufferIterator operator--(int){
+                       BufferIterator iter = *this;
+                       --_index;
+                       return iter;
+               }       
+
+               friend BufferIterator operator+(BufferIterator lhsiter, difference_type n){
+                       lhsiter._index += n;
+                       return lhsiter;
+               }
+
+               friend BufferIterator operator+(difference_type n, BufferIterator rhsiter){
+                       rhsiter._index += n;
+                       return rhsiter;
+               }
+               
+
+               BufferIterator& operator+=(difference_type n){
+                       _index += n;
+                       return *this;
+               }
+
+               friend BufferIterator operator-(BufferIterator lhsiter, difference_type n){
+                       lhsiter._index -= n;
+                       return lhsiter;
+               }
+
+               friend difference_type operator-(const BufferIterator& lhsiter, const BufferIterator& rhsiter){
+                       
+                       return lhsiter._index - rhsiter._index;
+               }
+
+               BufferIterator& operator-=(difference_type n){
+                       _index -= n;
+                       return *this;
+               }
+
+               bool operator==(const BufferIterator& other) const{
+                       if (!_comparable(other))
+                               return false;
+                       return ((_index == other._index)&&(_offset == other._offset));
+               }
+               
+               bool operator!=(const BufferIterator& other) const{
+                       if (!_comparable(other))
+                               return true;
+                       return ((_index != other._index)||(_offset != other._offset));
+               }
+
+               bool operator<(const BufferIterator& other) const {
+                       if (!_comparable(other))
+                               return false;
+                       return ((_index + _offset)<(other._index+other._offset));
+               }
+
+               bool operator>(const BufferIterator& other) const{
+                       if (!_comparable(other))
+                               return false;
+                       return ((_index + _offset)>(other._index+other._offset));
+               }
+
+               bool operator<=(const BufferIterator& other) const {
+                       if (!_comparable(other))
+                               return false;
+                       return ((_index + _offset)<=(other._index+other._offset));
+               }
+
+               bool operator>=(const BufferIterator& other) const {
+                       if (!_comparable(other))
+                               return false;
+                       return ((_index + _offset)>=(other._index+other._offset));
+               }
+       };
+};
+
+template<typename T>
+inline 
+bool CircularBuffer<T>::full() const{
+       return _size == _max_size;
+}
+
+template<typename T>
+inline 
+bool CircularBuffer<T>::empty() const{
+       return _size == 0;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::size_type CircularBuffer<T>::capacity() const{
+       return _max_size;
+}
+
+template<typename T>
+inline 
+void  CircularBuffer<T>::clear(){
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       _head = _tail = _size = 0;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::size_type CircularBuffer<T>::size() const{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       return _size;
+       }
+
+template<typename T>
+inline
+typename CircularBuffer<T>::reference CircularBuffer<T>::front() {
+       //std::lock_guard<std::mutex> _lck(_mtx);
+    // clyne
+       if(empty())
+               abort(); //throw std::length_error("front function called on empty buffer");
+       return _buff[_tail];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::reference CircularBuffer<T>::back() {
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       if(empty())
+               abort(); //throw std::length_error("back function called on empty buffer");
+       return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_reference CircularBuffer<T>::front() const{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       if(empty())
+               abort(); //throw std::length_error("front function called on empty buffer");
+       return _buff[_tail];
+}
+
+template<typename T>
+inline
+typename CircularBuffer<T>::const_reference CircularBuffer<T>::back() const{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       if(empty())
+               abort(); //throw std::length_error("back function called on empty buffer");
+       return _head == 0 ? _buff[_max_size - 1] : _buff[_head - 1];
+}
+
+template<typename T>
+inline
+void CircularBuffer<T>::push_back(const T& data){
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       //if(full())
+       //      _buff[_tail].~T();
+       _buff[_head] = data;
+       _increment_bufferstate();
+}
+
+template<typename T>
+inline
+void CircularBuffer<T>::push_back(T&& data) noexcept{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       _buff[_head] = std::move(data);
+       _increment_bufferstate();
+}
+
+
+template<typename T>
+inline 
+void CircularBuffer<T>::_increment_bufferstate(){
+       if(full())
+               _tail = (_tail + 1)%_max_size;
+       else
+               ++_size;
+       _head = (_head + 1)%_max_size;  
+}
+
+template<typename T>
+inline 
+void CircularBuffer<T>::pop_front(){
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       if(empty())
+               abort(); //throw std::length_error("pop_front called on empty buffer");
+       _decrement_bufferstate();
+}
+
+template<typename T>
+inline 
+void CircularBuffer<T>::_decrement_bufferstate(){
+       --_size;
+       _tail = (_tail + 1)%_max_size;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::reference CircularBuffer<T>::operator[](size_t index) {
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       if((index<0)||(index>=_size))
+               abort(); //throw std::out_of_range("Index is out of Range of buffer size");
+       index += _tail;
+       index %= _max_size;
+       return _buff[index];
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::const_reference CircularBuffer<T>::operator[](size_t index) const {
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       if((index<0)||(index>=_size))
+               abort(); //throw std::out_of_range("Index is out of Range of buffer size");
+       index += _tail;
+       index %= _max_size;
+       return _buff[index];
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::reference CircularBuffer<T>::at(size_t index) {
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       if((index<0)||(index>=_size))
+               abort(); //throw std::out_of_range("Index is out of Range of buffer size");
+       index += _tail;
+       index %= _max_size;
+       return _buff[index];
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::const_reference CircularBuffer<T>::at(size_t index) const {
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       if((index<0)||(index>=_size))
+               abort(); //throw std::out_of_range("Index is out of Range of buffer size");
+       index += _tail;
+       index %= _max_size;
+       return _buff[index];
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::iterator CircularBuffer<T>::begin() {
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = 0;
+       iter._reverse = false;
+       return iter;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::begin() const{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       const_iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = 0;
+       iter._reverse = false;
+       return iter;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::iterator CircularBuffer<T>::end() {
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = _size;
+       iter._reverse = false;
+       return iter;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::end() const{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       const_iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = _size;
+       iter._reverse = false;
+       return iter;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::cbegin() const noexcept{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       const_iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = 0;
+       iter._reverse = false;
+       return iter;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::cend() const noexcept{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       const_iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = _size;
+       iter._reverse = false;
+       return iter;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::iterator CircularBuffer<T>::rbegin() noexcept{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = 0;
+       iter._reverse = true;
+       return iter;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::rbegin() const noexcept{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       const_iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = 0;
+       iter._reverse = true;
+       return iter;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::iterator CircularBuffer<T>::rend()  noexcept{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = _size;
+       iter._reverse = true;
+       return iter;
+}
+
+template<typename T>
+inline 
+typename CircularBuffer<T>::const_iterator CircularBuffer<T>::rend() const noexcept{
+       //std::lock_guard<std::mutex> _lck(_mtx);
+       const_iterator iter;
+       iter._ptrToBuffer = this;
+       iter._offset = _tail;
+       iter._index = _size;
+       iter._reverse = true;
+       return iter;
+}
+
+#endif /* CIRCULAR_BUFFER_H */
diff --git a/src/gdt.cpp b/src/gdt.cpp
new file mode 100644 (file)
index 0000000..24d974b
--- /dev/null
@@ -0,0 +1,169 @@
+#include <array>
+#include <cstdint>
+
+struct gdt_entry_bits {
+    std::uint32_t limit_low              : 16;
+    std::uint32_t base_low               : 24;
+    std::uint32_t accessed               :  1;
+    std::uint32_t read_write             :  1; // readable for code, writable for data
+    std::uint32_t conforming_expand_down :  1; // conforming for code, expand down for data
+    std::uint32_t code                   :  1; // 1 for code, 0 for data
+    std::uint32_t code_data_segment      :  1; // should be 1 for everything but TSS and LDT
+    std::uint32_t DPL                    :  2; // privilege level
+    std::uint32_t present                :  1;
+    std::uint32_t limit_high             :  4;
+    std::uint32_t available              :  1; // only used in software; has no effect on hardware
+    std::uint32_t long_mode              :  1;
+    std::uint32_t big                    :  1; // 32-bit opcodes for code, uint32_t stack for data
+    std::uint32_t gran                   :  1; // 1 to use 4k page addressing, 0 for byte addressing
+    std::uint32_t base_high              :  8;
+} __attribute__((packed));
+
+struct TSSEntry
+{
+    std::uint32_t prevTSS;
+    std::uint32_t esp0;
+    std::uint32_t ss0;
+    std::uint32_t unused[23] = {};
+} __attribute__((packed));
+
+static TSSEntry tss = {
+    .prevTSS = 0,
+    .esp0 = 0,
+    .ss0 = 0x10
+};
+
+static const std::array<gdt_entry_bits, 6> gdt {{
+    {},
+    /* kernel_code = */ {
+        .limit_low = 0xFFFF,
+        .base_low = 0x0000,
+        .accessed = 0,
+        .read_write = 1,
+        .conforming_expand_down = 0,
+        .code = 1,
+        .code_data_segment = 1,
+        .DPL = 0,
+        .present = 1,
+        .limit_high = 0xF,
+        .available = 0,
+        .long_mode = 0,
+        .big = 1,
+        .gran = 1,
+        .base_high = 0x00
+    },
+    /* kernel_data = */ {
+        .limit_low = 0xFFFF,
+        .base_low = 0x0000,
+        .accessed = 0,
+        .read_write = 1,
+        .conforming_expand_down = 0,
+        .code = 0,
+        .code_data_segment = 1,
+        .DPL = 0,
+        .present = 1,
+        .limit_high = 0xF,
+        .available = 0,
+        .long_mode = 0,
+        .big = 1,
+        .gran = 1,
+        .base_high = 0x00
+    },
+    /* user_code = */ {
+        .limit_low = 0xFFFF,
+        .base_low = 0x0000,
+        .accessed = 0,
+        .read_write = 1,
+        .conforming_expand_down = 0,
+        .code = 1,
+        .code_data_segment = 1,
+        .DPL = 3,
+        .present = 1,
+        .limit_high = 0xF,
+        .available = 0,
+        .long_mode = 0,
+        .big = 1,
+        .gran = 1,
+        .base_high = 0x00
+    },
+    /* user_data = */ {
+        .limit_low = 0xFFFF,
+        .base_low = 0x0000,
+        .accessed = 0,
+        .read_write = 1,
+        .conforming_expand_down = 0,
+        .code = 0,
+        .code_data_segment = 1,
+        .DPL = 3,
+        .present = 1,
+        .limit_high = 0xF,
+        .available = 0,
+        .long_mode = 0,
+        .big = 1,
+        .gran = 1,
+        .base_high = 0x00
+    },
+    /* tss = */ {
+        .limit_low = sizeof(TSSEntry),
+        .base_low = (std::uint32_t)&tss & 0xFFFFFF,
+        .accessed = 1,
+        .read_write = 0,
+        .conforming_expand_down = 0,
+        .code = 1,
+        .code_data_segment = 0,
+        .DPL = 0,
+        .present = 1,
+        .limit_high = 0,
+        .available = 0,
+        .long_mode = 0,
+        .big = 0,
+        .gran = 0,
+        .base_high = (std::uint32_t)&tss >> 24
+    }
+}};
+
+void gdt_initialize()
+{
+    auto gdtr = reinterpret_cast<std::uint64_t>(gdt.data());
+    gdtr <<= 16;
+    gdtr |= gdt.size() * sizeof(gdt[0]);
+
+    asm volatile(R"(
+        lgdt %0
+        pushl $0x8
+        push $.setcs
+        ljmp *(%%esp)
+    .setcs:
+        add $8, %%esp
+        mov $0x10, %%eax
+        mov %%eax, %%ds
+        mov %%eax, %%es
+        mov %%eax, %%fs
+        mov %%eax, %%gs
+        mov %%eax, %%ss
+
+        mov $0x28, %%ax
+        ltr %%ax
+    )" :: "m"(gdtr));
+}
+
+void enter_user_mode(void (*func)())
+{
+    asm volatile("mov %%esp, %0" : "=r" (tss.esp0));
+
+    asm volatile(R"(
+        mov $0x23, %%ax
+        mov %%ax, %%ds
+        mov %%ax, %%es
+        mov %%ax, %%fs
+        mov %%ax, %%gs
+        mov %%esp, %%eax
+        push $0x23
+        push %%esp
+        pushf
+        push $0x1b
+        push %0
+        iret
+    )" :: "b"(func));
+}
+
diff --git a/src/gdt.hpp b/src/gdt.hpp
new file mode 100644 (file)
index 0000000..de5e8fc
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef GDT_HPP
+#define GDT_HPP
+
+void gdt_initialize();
+void enter_user_mode(void (*func)());
+
+#endif // GDT_HPP
+
diff --git a/src/idt.cpp b/src/idt.cpp
new file mode 100644 (file)
index 0000000..5380c9e
--- /dev/null
@@ -0,0 +1,126 @@
+#include "idt.hpp"
+#include "portio.hpp"
+#include "textoutput.hpp"
+
+#include <array>
+#include <cstdint>
+#include <utility>
+
+extern TextOutput& term;
+
+static constexpr unsigned InterruptCount = 49;
+
+static constexpr std::uint8_t TaskGate   = 0x5;
+static constexpr std::uint8_t IntrGate16 = 0x6;
+static constexpr std::uint8_t TrapGate16 = 0x7;
+static constexpr std::uint8_t IntrGate32 = 0xE;
+static constexpr std::uint8_t TrapGate32 = 0xF;
+
+struct idt_entry_bits {
+    std::uint32_t offset_low             : 16;
+    std::uint32_t segment_selector       : 16;
+    std::uint32_t rsvd                   :  8 = 0;
+    std::uint32_t gate_type              :  4;
+    std::uint32_t rsvd2                  :  1 = 0;
+    std::uint32_t dpl                    :  2;
+    std::uint32_t present                :  1;
+    std::uint32_t offset_high            : 16;
+} __attribute__((packed));
+
+static std::array<Callback, InterruptCount> callbacks;
+
+extern "C"
+void interruptGeneralHandler(Registers regs)
+{
+    const auto& inum = regs.inum;
+
+    if (inum >= 32) {
+        if (inum >= 40)
+            outb(0xA0, 0x20);
+
+        outb(0x20, 0x20);
+    }
+
+    if (inum < callbacks.size()) {
+        if (auto cb = callbacks[inum]; cb) {
+            asm volatile("cli");
+            cb(regs);
+            asm volatile("sti");
+        }
+    }
+}
+
+template<std::size_t N>
+struct StubEntry
+{
+    static constexpr bool HasError = N == 8 || (N >= 10 && N <= 14) || N == 17 || N == 30;
+
+    __attribute__((naked))
+    static void stub() {
+        if constexpr (!HasError)
+            asm volatile("push $0x0");
+
+        asm volatile(R"(
+            pusha
+            mov %%ds, %%eax
+            push %%eax
+            mov $0x10, %%ax
+            mov %%ax, %%ds
+            mov %%ax, %%es
+            mov %%ax, %%fs
+            mov %%ax, %%gs
+            push %0
+            cld
+            call interruptGeneralHandler
+            pop %%eax
+            pop %%eax
+            mov %%ax, %%ds
+            mov %%ax, %%es
+            mov %%ax, %%fs
+            mov %%ax, %%gs
+            popa
+            add $0x4, %%esp
+            iret
+        )" :: "i"(N));
+    }
+
+    static constexpr std::uint32_t segment(std::uint16_t gdt_idx, bool useLdt, std::uint16_t rpl) {
+        return gdt_idx | (useLdt ? 0x4 : 0x0) | (rpl & 0x3);
+    }
+
+    idt_entry_bits entry = {
+        .offset_low = (uint32_t)stub & 0xFFFF,
+        .segment_selector = segment(0x8, false, 0),
+        .gate_type = IntrGate32,
+        .dpl = 0,
+        .present = 1,
+        .offset_high = (uint32_t)stub >> 16
+    };
+
+    operator idt_entry_bits() const noexcept {
+        return entry;
+    }
+};
+
+static auto idt =
+    []<std::size_t... ints>(std::index_sequence<ints...>) {
+        return std::array<idt_entry_bits, 256> { StubEntry<ints>()... };
+    }(std::make_index_sequence<InterruptCount>{});
+
+void idt_initialize()
+{
+    idt[0x28].dpl = 3;
+
+    auto idtr = reinterpret_cast<std::uint64_t>(idt.data());
+    idtr <<= 16;
+    idtr |= idt.size() * sizeof(idt[0]);
+
+    asm volatile("lidt %0" :: "m"(idtr));
+}
+
+void idt_register_callback(std::size_t num, Callback cb)
+{
+    if (num < callbacks.size())
+        callbacks[num] = cb;
+}
+
diff --git a/src/idt.hpp b/src/idt.hpp
new file mode 100644 (file)
index 0000000..c5e7e47
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef IDT_HPP
+#define IDT_HPP
+
+#include <cstddef>
+#include <cstdint>
+
+struct Registers
+{
+    std::uint32_t inum;
+    std::uint32_t ds;
+    std::uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
+    std::uint32_t error;
+    std::uint32_t eip, cs, eflags;
+} __attribute__((packed));
+
+using Callback = void (*)(const Registers&);
+
+void idt_initialize();
+void idt_register_callback(std::size_t num, Callback cb);
+
+#endif // IDT_HPP
+
diff --git a/src/kernel.cpp b/src/kernel.cpp
new file mode 100644 (file)
index 0000000..ae3f153
--- /dev/null
@@ -0,0 +1,104 @@
+#include "acpi.hpp"
+#include "ata.hpp"
+#include "gdt.hpp"
+#include "idt.hpp"
+#include "keyboard.hpp"
+#include "memory.hpp"
+#include "multiboot.hpp"
+#include "pic.hpp"
+#include "pit.hpp"
+#include "portio.hpp"
+#include "tasking.hpp"
+#include "vgaterminal.hpp"
+
+static VGATerminal vga;
+TextOutput& term = vga;
+
+static volatile bool termBusy = false;
+
+void ata_probe(auto bus, ATA::Drive drv, const char *name)
+{
+    switch (bus.identify(drv)) {
+    case ATA::Type::ATA:
+        term.write("ata:");
+        term.write(name);
+        term.write(": ATA drive detected.\n");
+        break;
+    case ATA::Type::ATAPI:
+        term.write("ata:");
+        term.write(name);
+        term.write(": ATAPI drive detected.\n");
+        break;
+    default:
+        break;
+    }
+}
+
+void kernel_main(void) 
+{
+    term.write("Clyne's kernel, v2024\n\n");
+
+    if (!multiboot_initialize())
+        for (;;);
+
+    idt_register_callback(14, [](auto& regs) {
+        term.write("Page fault! eip=");
+        term.write(regs.eip);
+        term.write('\n');
+        for (;;);
+    });
+
+    acpi_initialize();
+    memory_initialize();
+    gdt_initialize();
+    pic_initialize();
+    idt_initialize();
+    pit_initialize();
+    keyboard_initialize();
+    asm volatile("sti");
+    tasking_initialize();
+    term.write("Tasking enabled.\n");
+
+    ATA::Bus<ATA::Primary> bus0;
+    ATA::Bus<ATA::Secondary> bus1;
+
+    ata_probe(bus0, ATA::Master, "0:0");
+    ata_probe(bus0, ATA::Slave,  "0:1");
+    ata_probe(bus1, ATA::Master, "1:0");
+    ata_probe(bus1, ATA::Slave,  "1:1");
+
+    idt_register_callback(0x28, [](auto& regs) {
+        term.write(static_cast<char>(regs.eax));
+    });
+
+    term.write("Entering user mode...\n");
+    enter_user_mode([] {
+        asm volatile("int $0x28" :: "a" ('Z'));
+        for (;;);
+    });
+
+    for (;;) {
+        const auto ch = keyboard_read();
+        if (ch)
+            term.write(*ch);
+
+        pit_delay_ms(10);
+    }
+}
+
+extern "C"
+void abort()
+{
+    term.write("!!! abort() called !!!");
+    asm volatile("cli");
+    for (;;);
+}
+
+extern "C"
+int __cxa_atexit(void (*)(void *), void *, void *)
+{
+    return 0;
+}
+
+int __dso_handle = 0;
+
diff --git a/src/keyboard.cpp b/src/keyboard.cpp
new file mode 100644 (file)
index 0000000..48dad02
--- /dev/null
@@ -0,0 +1,64 @@
+#include "circularbuffer.hpp"
+#include "idt.hpp"
+#include "keyboard.hpp"
+#include "portio.hpp"
+#include "vgaterminal.hpp"
+
+#include <array>
+#include <cstdint>
+
+extern TextOutput& term;
+
+static CircularBuffer<char> keyboardBuffer;
+static Port<0x60> keyboardPort;
+
+static const std::array<char, 0x59> ScanCodeSet1 {{
+    0, K_ESCAPE,
+    '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
+    '-', '=', '\b', '\t',
+    'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', '\n', K_CONTROL_L,
+    'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '\'', '`', K_SHIFT_L, '\\',
+    'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/',
+    K_SHIFT_R, '*', K_ALT_L, ' ', K_CAPS,
+    K_F1, K_F2, K_F3, K_F4, K_F5, K_F6, K_F7, K_F8, K_F9, K_F10,
+    K_NUM, K_SCROLL, '7', '8', '9', '-', '4', '5', '6', '+', '1', '2', '3', '0', '.',
+    0, 0, 0, // non-existant
+    K_F11, K_F12
+}};
+
+static inline bool isReleased(auto ch) {
+    return ch & 0x80;
+}
+
+static inline auto keycode(auto ch) {
+    return ch & 0x7F;
+}
+
+void keyboard_initialize()
+{
+    keyboardBuffer = CircularBuffer<char>(128);
+
+    idt_register_callback(33, [](auto&) {
+        const std::uint8_t kc = keyboardPort;
+
+        if (!isReleased(kc)) {
+            const auto ch = ScanCodeSet1[keycode(kc)];
+            //if (ch > 0)
+            //    term.write(ch);
+
+            keyboardBuffer.push_back(ch);
+        }
+    });
+}
+
+std::optional<char> keyboard_read()
+{
+    if (keyboardBuffer.empty()) {
+        return {};
+    } else {
+        const auto ch = keyboardBuffer.front();
+        keyboardBuffer.pop_front();
+        return ch;
+    }
+}
+
diff --git a/src/keyboard.hpp b/src/keyboard.hpp
new file mode 100644 (file)
index 0000000..694ff89
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef KEYBOARD_HPP
+#define KEYBOARD_HPP
+
+#include <optional>
+
+#define K_CONTROL_L -1
+#define K_SHIFT_L   -2
+#define K_ALT_L     -3
+#define K_CAPS      -4
+#define K_NUM       -5
+#define K_SCROLL    -6
+#define K_SHIFT_R   -7
+#define K_ESCAPE    -8
+#define K_F1        -10
+#define K_F2        -11
+#define K_F3        -12
+#define K_F4        -13
+#define K_F5        -14
+#define K_F6        -15
+#define K_F7        -16
+#define K_F8        -17
+#define K_F9        -18
+#define K_F10       -19
+#define K_F11       -20
+#define K_F12       -21
+
+void keyboard_initialize();
+
+std::optional<char> keyboard_read();
+
+#endif // KEYBOARD_HPP
+
diff --git a/src/memmove.cpp b/src/memmove.cpp
new file mode 100644 (file)
index 0000000..06e37df
--- /dev/null
@@ -0,0 +1,78 @@
+/* Taken from newlib... */
+
+#include <cstring>
+#include <cstddef>
+#include <climits>
+
+/* Nonzero if either X or Y is not aligned on a "long" boundary.  */
+#define UNALIGNED(X, Y) \
+  (((long)X & (sizeof (long) - 1)) | ((long)Y & (sizeof (long) - 1)))
+
+/* How many bytes are copied each iteration of the 4X unrolled loop.  */
+#define BIGBLOCKSIZE    (sizeof (long) << 2)
+
+/* How many bytes are copied each iteration of the word copy loop.  */
+#define LITTLEBLOCKSIZE (sizeof (long))
+
+/* Threshhold for punting to the byte copier.  */
+#define TOO_SMALL(LEN)  ((LEN) < BIGBLOCKSIZE)
+
+extern "C"
+void *memmove (void *dst_void, const void *src_void, size_t length)
+{
+  char *dst = reinterpret_cast<char *>(dst_void);
+  const char *src = reinterpret_cast<const char *>(src_void);
+  long *aligned_dst;
+  const long *aligned_src;
+
+  if (src < dst && dst < src + length)
+    {
+      /* Destructive overlap...have to copy backwards */
+      src += length;
+      dst += length;
+      while (length--)
+       {
+         *--dst = *--src;
+       }
+    }
+  else
+    {
+      /* Use optimizing algorithm for a non-destructive copy to closely 
+         match memcpy. If the size is small or either SRC or DST is unaligned,
+         then punt into the byte copy loop.  This should be rare.  */
+      if (!TOO_SMALL(length) && !UNALIGNED (src, dst))
+        {
+          aligned_dst = (long*)dst;
+          aligned_src = (long*)src;
+
+          /* Copy 4X long words at a time if possible.  */
+          while (length >= BIGBLOCKSIZE)
+            {
+              *aligned_dst++ = *aligned_src++;
+              *aligned_dst++ = *aligned_src++;
+              *aligned_dst++ = *aligned_src++;
+              *aligned_dst++ = *aligned_src++;
+              length -= BIGBLOCKSIZE;
+            }
+
+          /* Copy one long word at a time if possible.  */
+          while (length >= LITTLEBLOCKSIZE)
+            {
+              *aligned_dst++ = *aligned_src++;
+              length -= LITTLEBLOCKSIZE;
+            }
+
+          /* Pick up any residual with a byte copier.  */
+          dst = (char*)aligned_dst;
+          src = (char*)aligned_src;
+        }
+
+      while (length--)
+        {
+          *dst++ = *src++;
+        }
+    }
+
+  return dst_void;
+}
+
diff --git a/src/memory.cpp b/src/memory.cpp
new file mode 100644 (file)
index 0000000..108c240
--- /dev/null
@@ -0,0 +1,107 @@
+#include "textoutput.hpp"
+
+#include <array>
+#include <cstdint>
+
+struct PageDirectory
+{
+    static constexpr std::uint32_t NotPresent = 0x2;
+
+    PageDirectory(): value(NotPresent) {}
+    PageDirectory(void *addr): value(reinterpret_cast<std::uint32_t>(addr) | 7) {}
+
+    std::uint32_t value;
+};
+static_assert(sizeof(PageDirectory) == sizeof(std::uint32_t));
+
+extern std::uint32_t lowerMem;
+extern std::uint32_t upperMem;
+extern TextOutput& term;
+
+static std::uintptr_t lowerFree = 0x400;
+static std::uintptr_t upperFree = 0x100000;
+
+alignas(4096)
+static std::array<PageDirectory, 1024> pageDirectory;
+
+alignas(4096)
+static std::array<std::uint32_t, 1024> pageTable;
+
+void memory_initialize()
+{
+    lowerMem -= 1024;
+
+    const auto totalKb = (lowerMem + upperMem) / 1024u;
+
+    term.write("Claiming ");
+    term.write(totalKb);
+    term.write(" kB for allocations...\n");
+
+    std::uint32_t addr = 0;
+    for (auto& p : pageTable) {
+        p = addr | 7; // supervisor, r/w, present
+        addr += 0x1000;
+    }
+
+    pageDirectory[0] = PageDirectory(pageTable.data());
+
+    asm volatile(R"(
+        mov %%eax, %%cr3
+        mov %%cr0, %%eax
+        or $0x80000000, %%eax
+        mov %%eax, %%cr0
+    )" :: "a"(pageDirectory.data()));
+
+    term.write("Paging enabled.\n");
+}
+
+static void *memory_alloc(std::size_t size)
+{
+    void *ret = nullptr;
+
+    if (lowerMem > size) {
+        ret = reinterpret_cast<void *>(lowerFree);
+        lowerFree += size;
+        lowerMem -= size;
+    } else if (upperMem > size) {
+        ret = reinterpret_cast<void *>(upperFree);
+        upperFree += size;
+        upperMem -= size;
+    } else {
+        // Uh oh!
+        term.write("!!! Kernel allocation failed !!!");
+    }
+
+    return ret;
+}
+
+void *operator new(std::size_t size)
+{
+    return memory_alloc(size);
+}
+
+void *operator new[](std::size_t size)
+{
+    return memory_alloc(size);
+}
+
+void operator delete(void *)
+{
+
+}
+
+void operator delete[](void *)
+{
+
+}
+
+void operator delete(void *, std::size_t)
+{
+
+}
+
+void operator delete[](void *, std::size_t)
+{
+
+}
+
diff --git a/src/memory.hpp b/src/memory.hpp
new file mode 100644 (file)
index 0000000..0467bf6
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef MEMORY_HPP
+#define MEMORY_HPP
+
+#include <cstddef>
+#include <type_traits>
+
+template<typename T>
+struct kallocator
+{
+    using value_type = T;
+    using size_type = std::size_t;
+    using difference_type = std::ptrdiff_t;
+    using propagate_on_container_move_assignment = std::true_type;
+    using is_always_equal = std::true_type;
+
+    template<class U>
+    struct rebind {
+        typedef kallocator<U> other;
+    };
+
+    kallocator() = default;
+
+    template<typename U>
+    kallocator(const kallocator<U>&) noexcept {}
+
+    T* allocate(std::size_t n) {
+        return new T[n];
+    }
+
+    void deallocate([[maybe_unused]] T* p, [[maybe_unused]] std::size_t n) {
+
+    }
+};
+
+void memory_initialize();
+
+#endif // MEMORY_HPP
+
diff --git a/src/multiboot.cpp b/src/multiboot.cpp
new file mode 100644 (file)
index 0000000..46c505b
--- /dev/null
@@ -0,0 +1,92 @@
+#include "textoutput.hpp"
+
+#include <cstdint>
+
+extern TextOutput& term;
+
+struct multiboot2_tag
+{
+    alignas(8)
+    std::uint16_t id;
+    std::uint16_t flags;
+    std::uint32_t length;
+    std::uint32_t data[1];
+} __attribute__((packed));
+
+template<int N>
+struct multiboot2
+{
+    static constexpr std::uint32_t MAGIC    = 0xE85250D6;
+    static constexpr std::uint32_t FLAGS    = 0;
+    static constexpr std::uint32_t LENGTH   = 16;
+    static constexpr std::uint32_t CHECKSUM = -(MAGIC + FLAGS + LENGTH);
+
+    alignas(8)
+    std::uint32_t magic = MAGIC;
+    std::uint32_t flags = FLAGS;
+    std::uint32_t length = LENGTH;
+    std::uint32_t checksum = CHECKSUM;
+
+    multiboot2_tag tags[N];
+} __attribute__((packed));
+
+__attribute__((section(".multiboot2")))
+multiboot2 multibootHeader = {
+    .tags = {
+        {
+            1, 0, sizeof(multiboot2_tag) + sizeof(std::uint32_t),
+            {4}
+        },
+        {
+            0, 0, 8, {}
+        }
+    }
+};
+
+std::uint32_t multiboot_magic;
+std::uint32_t *multiboot_ptr;
+
+std::uint32_t lowerMem = 0;
+std::uint32_t upperMem = 0;
+std::uint32_t *acpiRsdp = nullptr;
+std::uint32_t *acpiRsdpV2 = nullptr;
+
+bool multiboot_initialize()
+{
+    if (multiboot_magic != 0x36d76289) {
+        term.write("Not multiboot!");
+        return false;
+    }
+
+    term.write("Found multiboot headers: ");
+
+    auto ptr = multiboot_ptr + 2;
+    while (ptr[0] != 0 && ptr[1] != 8) {
+        term.write(ptr[0]);
+        term.write(", ");
+
+        switch (ptr[0]) {
+        case 4:
+            lowerMem = ptr[2] * 1024;
+            upperMem = ptr[3] * 1024;
+            break;
+        case 14:
+            acpiRsdp = ptr + 2;
+            break;
+        case 15:
+            acpiRsdpV2 = ptr + 2;
+            break;
+        default:
+            break;
+        }
+    
+        auto next = reinterpret_cast<std::uintptr_t>(ptr);
+        next += ptr[1];
+        next = (next + 7) & ~7;
+        ptr = reinterpret_cast<std::uint32_t *>(next);
+    }
+
+    term.write('\n');
+    return true;
+}
+
diff --git a/src/multiboot.hpp b/src/multiboot.hpp
new file mode 100644 (file)
index 0000000..9916850
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef MULTIBOOT_HPP
+#define MULTIBOOT_HPP
+
+bool multiboot_initialize();
+
+#endif // MULTIBOOT_HPP
+
diff --git a/src/pic.cpp b/src/pic.cpp
new file mode 100644 (file)
index 0000000..437f384
--- /dev/null
@@ -0,0 +1,63 @@
+#include "pic.hpp"
+
+#include "portio.hpp"
+
+#define PIC1           0x20            /* IO base address for master PIC */
+#define PIC2           0xA0            /* IO base address for slave PIC */
+#define PIC1_COMMAND   PIC1
+#define PIC1_DATA      (PIC1+1)
+#define PIC2_COMMAND   PIC2
+#define PIC2_DATA      (PIC2+1)
+
+#define PIC_EOI                0x20            /* End-of-interrupt command code */
+
+#define ICW1_ICW4    0x01              /* Indicates that ICW4 will be present */
+#define ICW1_SINGLE    0x02            /* Single (cascade) mode */
+#define ICW1_INTERVAL4    0x04         /* Call address interval 4 (8) */
+#define ICW1_LEVEL    0x08             /* Level triggered (edge) mode */
+#define ICW1_INIT    0x10              /* Initialization - required! */
+
+#define ICW4_8086    0x01              /* 8086/88 (MCS-80/85) mode */
+#define ICW4_AUTO    0x02              /* Auto (normal) EOI */
+#define ICW4_BUF_SLAVE    0x08         /* Buffered mode/slave */
+#define ICW4_BUF_MASTER    0x0C                /* Buffered mode/master */
+#define ICW4_SFNM    0x10              /* Special fully nested (not) */
+
+void pic_initialize()
+{
+    constexpr int offset1 = 0x20, offset2 = 0x28;
+    std::uint8_t a1, a2;
+    
+    a1 = inb(PIC1_DATA);                        // save masks
+    a2 = inb(PIC2_DATA);
+    
+    outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);  // starts the initialization sequence (in cascade mode)
+    io_wait();
+    outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
+    io_wait();
+    outb(PIC1_DATA, offset1);                 // ICW2: Master PIC vector offset
+    io_wait();
+    outb(PIC2_DATA, offset2);                 // ICW2: Slave PIC vector offset
+    io_wait();
+    outb(PIC1_DATA, 4);                      // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100)
+    io_wait();
+    outb(PIC2_DATA, 2);                       // ICW3: tell Slave PIC its cascade identity (0000 0010)
+    io_wait();
+    
+    outb(PIC1_DATA, ICW4_8086);               // ICW4: have the PICs use 8086 mode (and not 8080 mode)
+    io_wait();
+    outb(PIC2_DATA, ICW4_8086);
+    io_wait();
+    
+    outb(PIC1_DATA, a1);   // restore saved masks.
+    outb(PIC2_DATA, a2);
+}
+
+void pic_eoi(std::uint8_t irq)
+{
+    if (irq >= 8)
+        outb(PIC2_COMMAND, PIC_EOI);
+
+    outb(PIC1_COMMAND, PIC_EOI);
+}
+
diff --git a/src/pic.hpp b/src/pic.hpp
new file mode 100644 (file)
index 0000000..17abd55
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef PIC_HPP
+#define PIC_HPP
+
+#include <cstdint>
+
+/* reinitialize the PIC controllers, giving them specified vector offsets
+   rather than 8h and 70h, as configured by default */
+void pic_initialize();
+void pic_eoi(std::uint8_t irq);
+
+#endif // PIC_HPP
+
diff --git a/src/pit.cpp b/src/pit.cpp
new file mode 100644 (file)
index 0000000..964522b
--- /dev/null
@@ -0,0 +1,41 @@
+#include "pit.hpp"
+#include "idt.hpp"
+#include "portio.hpp"
+#include "tasking.hpp"
+
+constexpr std::uint32_t Frequency = 1000;
+
+static volatile std::uint32_t ticks = 0;
+
+static void timer_callback(const Registers& regs)
+{
+    ticks = ticks + 1;
+
+    schedule(regs);
+}
+
+void pit_initialize()
+{
+   // Firstly, register our timer callback.
+   idt_register_callback(32, timer_callback);
+
+   // The value we send to the PIT is the value to divide it's input clock
+   // (1193180 Hz) by, to get our required frequency. Important to note is
+   // that the divisor must be small enough to fit into 16-bits.
+   const auto divisor = 1193180ul / Frequency;
+
+   // Send the command byte.
+   outb(0x43, 0x36);
+
+   // Send the frequency divisor.
+   outb(0x40, divisor & 0xFF);
+   outb(0x40, (divisor >> 8) & 0xFF);
+}
+
+void pit_delay_ms(std::int32_t ms)
+{
+    const auto end = ticks + ms;
+    while (static_cast<std::int32_t>(end - ticks) > 0)
+        asm volatile("nop");
+}
+
diff --git a/src/pit.hpp b/src/pit.hpp
new file mode 100644 (file)
index 0000000..55bcde9
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef PIT_HPP
+#define PIT_HPP
+
+#include <cstdint>
+
+void pit_initialize();
+void pit_delay_ms(std::int32_t ms);
+
+#endif // PIT_HPP
+
diff --git a/src/portio.hpp b/src/portio.hpp
new file mode 100644 (file)
index 0000000..7636c14
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef PORTIO_HPP
+#define PORTIO_HPP
+
+#include <cstdint>
+
+inline void outb(std::uint16_t port, std::uint8_t val)
+{
+    asm volatile("out %%al, %%dx" :: "a"(val), "Nd"(port) : "memory");
+}
+
+inline std::uint8_t inb(std::uint16_t port)
+{
+    std::uint8_t val;
+    asm volatile("inb %%dx" : "=a"(val) : "Nd"(port) : "memory");
+    return val;
+}
+
+inline void outw(std::uint16_t port, std::uint16_t val)
+{
+    asm volatile("out %%ax, %%dx" :: "a"(val), "Nd"(port) : "memory");
+}
+
+inline std::uint16_t inw(std::uint16_t port)
+{
+    std::uint16_t val;
+    asm volatile("inw %%dx" : "=a"(val) : "Nd"(port) : "memory");
+    return val;
+}
+
+inline void io_wait()
+{
+    outb(0x80, 0);
+}
+
+template<std::uint16_t Addr>
+struct Port
+{
+    Port() = default;
+
+    template<typename T>
+    auto operator=(T val) noexcept {
+        if constexpr (sizeof(T) == 1)
+            outb(Addr, val);
+        else if constexpr (sizeof(T) == 2)
+            outw(Addr, val);
+
+        return *this;
+    }
+
+    template<typename T>
+    operator T() const noexcept {
+        if constexpr (sizeof(T) == 1)
+            return inb(Addr);
+        else if constexpr (sizeof(T) == 2)
+            return inw(Addr);
+    }
+
+    template<typename T>
+    bool operator==(T val) const noexcept {
+        T dat = *this;
+        return dat == val;
+    }
+
+    template<typename T>
+    auto operator&(T val) const noexcept {
+        T dat = *this;
+        return dat & val;
+    }
+};
+
+#endif // PORTIO_HPP
+
diff --git a/src/tasking.cpp b/src/tasking.cpp
new file mode 100644 (file)
index 0000000..1b78011
--- /dev/null
@@ -0,0 +1,92 @@
+#include "tasking.hpp"
+
+#include <array>
+
+struct Task
+{
+    enum class State {
+        Invalid,
+        Staging,
+        Staged,
+        Running
+    };
+
+    using enum State;
+
+    std::uint32_t esp;
+    std::uint32_t ebp;
+    State state = State::Invalid;
+};
+
+static std::array<Task, 4> tasks;
+static int current = -1;
+
+void schedule(const Registers&)
+{
+    if (current < 0)
+        return;
+
+    asm volatile(R"(
+        mov %%esp, %0
+        mov %%ebp, %1
+    )" : "=m" (tasks[current].esp), "=m" (tasks[current].ebp));
+
+    do {
+        if (++current >= static_cast<int>(tasks.size()))
+            current = 0;
+    } while (tasks[current].state == Task::Invalid || tasks[current].state == Task::Staging);
+
+    asm volatile(R"(
+        mov %0, %%esp
+        mov %1, %%ebp
+    )" :: "m" (tasks[current].esp), "m" (tasks[current].ebp));
+
+    if (tasks[current].state == Task::Staged) {
+        tasks[current].state = Task::Running;
+        asm volatile(R"(
+            pop %eax
+            popa
+            add $0x4, %esp
+            iret
+        )");
+    }
+}
+
+void tasking_initialize()
+{
+    tasks[0].state = Task::Running;
+    current = 0;
+    asm volatile("int $0x20");
+}
+
+bool tasking_spawn(void (*entry)(), unsigned ssize)
+{
+    unsigned i;
+    for (i = 0; i < tasks.size(); ++i) {
+        if (tasks[i].state == Task::Invalid)
+            break;
+    }
+
+    if (i >= tasks.size())
+        return false;
+
+    tasks[i].state = Task::Staging;
+
+    auto stack = reinterpret_cast<std::uint32_t>(new std::uint8_t[ssize]);
+    const auto stackend = stack + ssize;
+    const auto regbase = stackend - sizeof(Registers);
+    auto r = reinterpret_cast<Registers *>(regbase);
+    r->ebp = stackend;
+    r->esp = stackend;
+    r->eip = reinterpret_cast<std::uint32_t>(entry);
+    r->cs = 0x8;
+    asm volatile("pushfl; pop %%eax" : "=a"(r->eflags));
+
+    tasks[i] = Task {
+        .esp = regbase,
+        .ebp = stackend,
+        .state = Task::Staged
+    };
+    return true;
+}
+
diff --git a/src/tasking.hpp b/src/tasking.hpp
new file mode 100644 (file)
index 0000000..64a738e
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef TASKING_HPP
+#define TASKING_HPP
+
+#include "idt.hpp"
+
+void tasking_initialize();
+bool tasking_spawn(void (*entry)(), unsigned ssize);
+
+void schedule(const Registers& regs);
+
+#endif // TASKING_HPP
+
diff --git a/src/textoutput.hpp b/src/textoutput.hpp
new file mode 100644 (file)
index 0000000..7ef12fa
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef TEXTOUTPUT_HPP
+#define TEXTOUTPUT_HPP
+
+class TextOutput
+{
+public:
+    virtual void write(char c) noexcept = 0;
+
+    void write(const char *s) noexcept {
+        if (s) {
+            while (*s)
+                write(*s++);
+        }
+    }
+
+    void write(int n) noexcept {
+        char buf[32];
+        auto ptr = buf + sizeof(buf);
+
+        *--ptr = '\0';
+        do {
+            *--ptr = "0123456789"[n % 10];
+            n /= 10;
+        } while (n);
+
+        write(ptr);
+    }
+
+    void write(unsigned n) noexcept {
+        char buf[32];
+        auto ptr = buf + sizeof(buf);
+
+        *--ptr = '\0';
+        do {
+            *--ptr = "0123456789"[n % 10];
+            n /= 10;
+        } while (n);
+
+        write(ptr);
+    }
+};
+
+#endif // TEXTOUTPUT_HPP
+
diff --git a/src/vgaterminal.cpp b/src/vgaterminal.cpp
new file mode 100644 (file)
index 0000000..5f86081
--- /dev/null
@@ -0,0 +1,63 @@
+#include "portio.hpp"
+#include "vgaterminal.hpp"
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+
+void VGATerminal::write(char c) noexcept
+{
+    checkpos();
+
+    switch (c) {
+    case '\b':
+        if (offset % Width) {
+            --offset;
+            put(' ');
+            --offset;
+        }
+        break;
+    case '\n':
+        offset += Width;
+        [[fallthrough]];
+    case '\r':
+        offset -= offset % Width;
+        break;
+    default:
+        put(c);
+        break;
+    }
+
+    updatecursor();
+}
+
+void VGATerminal::put(char c) noexcept
+{
+    std::uint16_t cell = c
+        | (std::to_underlying(foreground) << 8)
+        | (std::to_underlying(background) << 12);
+
+    auto ptr = reinterpret_cast<std::uint16_t *>(Videoram);
+    ptr[offset++] = cell;
+}
+
+void VGATerminal::checkpos() noexcept
+{
+    if (offset >= Width * Height) {
+        auto ptr = reinterpret_cast<std::uint16_t *>(Videoram);
+        const auto end = ptr + Width * Height;
+        std::copy(ptr + Width, end, ptr);
+        std::fill(end - Width, end, 0);
+        offset = Width * Height - Width;
+    }
+}
+
+void VGATerminal::updatecursor() const noexcept
+{
+    outb(0x03d4, 0x0f);
+    outb(0x03d5, static_cast<std::uint8_t>(offset));
+    outb(0x03d4, 0x0e);
+    outb(0x03d5, static_cast<std::uint8_t>(offset >> 8));
+}
+
diff --git a/src/vgaterminal.hpp b/src/vgaterminal.hpp
new file mode 100644 (file)
index 0000000..9f8d5f3
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef VGATERMINAL_HPP
+#define VGATERMINAL_HPP
+
+#include "textoutput.hpp"
+
+#include <cstddef>
+#include <cstdint>
+
+class VGATerminal : public TextOutput
+{
+public:
+    enum class Color : std::uint8_t
+    {
+       Black = 0,
+       Blue,
+       Green,
+       Cyan,
+       Red,
+       Magenta,
+       Brown,
+       LightGray,
+       DarkGray,
+       LightBlue,
+       LightGreen,
+       LightCyan,
+       LightRed,
+       LightMagenta,
+       LightBrown,
+       White
+    };
+
+    using enum Color;
+
+    virtual void write(char c) noexcept final;
+
+private:
+    static constexpr std::uintptr_t Videoram = 0xB8000;
+    static constexpr unsigned Width = 80;
+    static constexpr unsigned Height = 25;
+
+    unsigned offset = 0;
+    Color foreground = LightGray;
+    Color background = Black;
+
+    void put(char c) noexcept;
+    void checkpos() noexcept;
+    void updatecursor() const noexcept;
+};
+
+#endif // VGATERMINAL_HPP
+
diff --git a/tasking.cpp b/tasking.cpp
deleted file mode 100644 (file)
index 1b78011..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-#include "tasking.hpp"
-
-#include <array>
-
-struct Task
-{
-    enum class State {
-        Invalid,
-        Staging,
-        Staged,
-        Running
-    };
-
-    using enum State;
-
-    std::uint32_t esp;
-    std::uint32_t ebp;
-    State state = State::Invalid;
-};
-
-static std::array<Task, 4> tasks;
-static int current = -1;
-
-void schedule(const Registers&)
-{
-    if (current < 0)
-        return;
-
-    asm volatile(R"(
-        mov %%esp, %0
-        mov %%ebp, %1
-    )" : "=m" (tasks[current].esp), "=m" (tasks[current].ebp));
-
-    do {
-        if (++current >= static_cast<int>(tasks.size()))
-            current = 0;
-    } while (tasks[current].state == Task::Invalid || tasks[current].state == Task::Staging);
-
-    asm volatile(R"(
-        mov %0, %%esp
-        mov %1, %%ebp
-    )" :: "m" (tasks[current].esp), "m" (tasks[current].ebp));
-
-    if (tasks[current].state == Task::Staged) {
-        tasks[current].state = Task::Running;
-        asm volatile(R"(
-            pop %eax
-            popa
-            add $0x4, %esp
-            iret
-        )");
-    }
-}
-
-void tasking_initialize()
-{
-    tasks[0].state = Task::Running;
-    current = 0;
-    asm volatile("int $0x20");
-}
-
-bool tasking_spawn(void (*entry)(), unsigned ssize)
-{
-    unsigned i;
-    for (i = 0; i < tasks.size(); ++i) {
-        if (tasks[i].state == Task::Invalid)
-            break;
-    }
-
-    if (i >= tasks.size())
-        return false;
-
-    tasks[i].state = Task::Staging;
-
-    auto stack = reinterpret_cast<std::uint32_t>(new std::uint8_t[ssize]);
-    const auto stackend = stack + ssize;
-    const auto regbase = stackend - sizeof(Registers);
-    auto r = reinterpret_cast<Registers *>(regbase);
-    r->ebp = stackend;
-    r->esp = stackend;
-    r->eip = reinterpret_cast<std::uint32_t>(entry);
-    r->cs = 0x8;
-    asm volatile("pushfl; pop %%eax" : "=a"(r->eflags));
-
-    tasks[i] = Task {
-        .esp = regbase,
-        .ebp = stackend,
-        .state = Task::Staged
-    };
-    return true;
-}
-
diff --git a/tasking.hpp b/tasking.hpp
deleted file mode 100644 (file)
index 64a738e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef TASKING_HPP
-#define TASKING_HPP
-
-#include "idt.hpp"
-
-void tasking_initialize();
-bool tasking_spawn(void (*entry)(), unsigned ssize);
-
-void schedule(const Registers& regs);
-
-#endif // TASKING_HPP
-
diff --git a/textoutput.hpp b/textoutput.hpp
deleted file mode 100644 (file)
index 7ef12fa..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef TEXTOUTPUT_HPP
-#define TEXTOUTPUT_HPP
-
-class TextOutput
-{
-public:
-    virtual void write(char c) noexcept = 0;
-
-    void write(const char *s) noexcept {
-        if (s) {
-            while (*s)
-                write(*s++);
-        }
-    }
-
-    void write(int n) noexcept {
-        char buf[32];
-        auto ptr = buf + sizeof(buf);
-
-        *--ptr = '\0';
-        do {
-            *--ptr = "0123456789"[n % 10];
-            n /= 10;
-        } while (n);
-
-        write(ptr);
-    }
-
-    void write(unsigned n) noexcept {
-        char buf[32];
-        auto ptr = buf + sizeof(buf);
-
-        *--ptr = '\0';
-        do {
-            *--ptr = "0123456789"[n % 10];
-            n /= 10;
-        } while (n);
-
-        write(ptr);
-    }
-};
-
-#endif // TEXTOUTPUT_HPP
-
diff --git a/vgaterminal.cpp b/vgaterminal.cpp
deleted file mode 100644 (file)
index 5f86081..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "portio.hpp"
-#include "vgaterminal.hpp"
-
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <utility>
-
-void VGATerminal::write(char c) noexcept
-{
-    checkpos();
-
-    switch (c) {
-    case '\b':
-        if (offset % Width) {
-            --offset;
-            put(' ');
-            --offset;
-        }
-        break;
-    case '\n':
-        offset += Width;
-        [[fallthrough]];
-    case '\r':
-        offset -= offset % Width;
-        break;
-    default:
-        put(c);
-        break;
-    }
-
-    updatecursor();
-}
-
-void VGATerminal::put(char c) noexcept
-{
-    std::uint16_t cell = c
-        | (std::to_underlying(foreground) << 8)
-        | (std::to_underlying(background) << 12);
-
-    auto ptr = reinterpret_cast<std::uint16_t *>(Videoram);
-    ptr[offset++] = cell;
-}
-
-void VGATerminal::checkpos() noexcept
-{
-    if (offset >= Width * Height) {
-        auto ptr = reinterpret_cast<std::uint16_t *>(Videoram);
-        const auto end = ptr + Width * Height;
-        std::copy(ptr + Width, end, ptr);
-        std::fill(end - Width, end, 0);
-        offset = Width * Height - Width;
-    }
-}
-
-void VGATerminal::updatecursor() const noexcept
-{
-    outb(0x03d4, 0x0f);
-    outb(0x03d5, static_cast<std::uint8_t>(offset));
-    outb(0x03d4, 0x0e);
-    outb(0x03d5, static_cast<std::uint8_t>(offset >> 8));
-}
-
diff --git a/vgaterminal.hpp b/vgaterminal.hpp
deleted file mode 100644 (file)
index 9f8d5f3..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef VGATERMINAL_HPP
-#define VGATERMINAL_HPP
-
-#include "textoutput.hpp"
-
-#include <cstddef>
-#include <cstdint>
-
-class VGATerminal : public TextOutput
-{
-public:
-    enum class Color : std::uint8_t
-    {
-       Black = 0,
-       Blue,
-       Green,
-       Cyan,
-       Red,
-       Magenta,
-       Brown,
-       LightGray,
-       DarkGray,
-       LightBlue,
-       LightGreen,
-       LightCyan,
-       LightRed,
-       LightMagenta,
-       LightBrown,
-       White
-    };
-
-    using enum Color;
-
-    virtual void write(char c) noexcept final;
-
-private:
-    static constexpr std::uintptr_t Videoram = 0xB8000;
-    static constexpr unsigned Width = 80;
-    static constexpr unsigned Height = 25;
-
-    unsigned offset = 0;
-    Color foreground = LightGray;
-    Color background = Black;
-
-    void put(char c) noexcept;
-    void checkpos() noexcept;
-    void updatecursor() const noexcept;
-};
-
-#endif // VGATERMINAL_HPP
-