From 19d9a04e36e7fb96eebe89e24311408460c29a70 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Mon, 30 Sep 2024 11:08:46 -0400 Subject: reorganize files --- .gitignore | 3 +- Makefile | 44 ++-- acpi.cpp | 51 ----- acpi.hpp | 7 - ata.cpp | 0 ata.hpp | 131 ----------- boot.cpp | 36 ---- circularbuffer.hpp | 573 ------------------------------------------------- gdt.cpp | 169 --------------- gdt.hpp | 8 - idt.cpp | 126 ----------- idt.hpp | 22 -- kernel.cpp | 104 --------- keyboard.cpp | 64 ------ keyboard.hpp | 32 --- memmove.cpp | 78 ------- memory.cpp | 107 --------- memory.hpp | 38 ---- multiboot.cpp | 92 -------- multiboot.hpp | 7 - pic.cpp | 63 ------ pic.hpp | 12 -- pit.cpp | 41 ---- pit.hpp | 10 - portio.hpp | 72 ------- src/acpi.cpp | 51 +++++ src/acpi.hpp | 7 + src/ata.cpp | 0 src/ata.hpp | 131 +++++++++++ src/boot.cpp | 36 ++++ src/circularbuffer.hpp | 573 +++++++++++++++++++++++++++++++++++++++++++++++++ src/gdt.cpp | 169 +++++++++++++++ src/gdt.hpp | 8 + src/idt.cpp | 126 +++++++++++ src/idt.hpp | 22 ++ src/kernel.cpp | 104 +++++++++ src/keyboard.cpp | 64 ++++++ src/keyboard.hpp | 32 +++ src/memmove.cpp | 78 +++++++ src/memory.cpp | 107 +++++++++ src/memory.hpp | 38 ++++ src/multiboot.cpp | 92 ++++++++ src/multiboot.hpp | 7 + src/pic.cpp | 63 ++++++ src/pic.hpp | 12 ++ src/pit.cpp | 41 ++++ src/pit.hpp | 10 + src/portio.hpp | 72 +++++++ src/tasking.cpp | 92 ++++++++ src/tasking.hpp | 12 ++ src/textoutput.hpp | 44 ++++ src/vgaterminal.cpp | 63 ++++++ src/vgaterminal.hpp | 51 +++++ tasking.cpp | 92 -------- tasking.hpp | 12 -- textoutput.hpp | 44 ---- vgaterminal.cpp | 63 ------ vgaterminal.hpp | 51 ----- 58 files changed, 2124 insertions(+), 2133 deletions(-) delete mode 100644 acpi.cpp delete mode 100644 acpi.hpp delete mode 100644 ata.cpp delete mode 100644 ata.hpp delete mode 100644 boot.cpp delete mode 100644 circularbuffer.hpp delete mode 100644 gdt.cpp delete mode 100644 gdt.hpp delete mode 100644 idt.cpp delete mode 100644 idt.hpp delete mode 100644 kernel.cpp delete mode 100644 keyboard.cpp delete mode 100644 keyboard.hpp delete mode 100644 memmove.cpp delete mode 100644 memory.cpp delete mode 100644 memory.hpp delete mode 100644 multiboot.cpp delete mode 100644 multiboot.hpp delete mode 100644 pic.cpp delete mode 100644 pic.hpp delete mode 100644 pit.cpp delete mode 100644 pit.hpp delete mode 100644 portio.hpp create mode 100644 src/acpi.cpp create mode 100644 src/acpi.hpp create mode 100644 src/ata.cpp create mode 100644 src/ata.hpp create mode 100644 src/boot.cpp create mode 100644 src/circularbuffer.hpp create mode 100644 src/gdt.cpp create mode 100644 src/gdt.hpp create mode 100644 src/idt.cpp create mode 100644 src/idt.hpp create mode 100644 src/kernel.cpp create mode 100644 src/keyboard.cpp create mode 100644 src/keyboard.hpp create mode 100644 src/memmove.cpp create mode 100644 src/memory.cpp create mode 100644 src/memory.hpp create mode 100644 src/multiboot.cpp create mode 100644 src/multiboot.hpp create mode 100644 src/pic.cpp create mode 100644 src/pic.hpp create mode 100644 src/pit.cpp create mode 100644 src/pit.hpp create mode 100644 src/portio.hpp create mode 100644 src/tasking.cpp create mode 100644 src/tasking.hpp create mode 100644 src/textoutput.hpp create mode 100644 src/vgaterminal.cpp create mode 100644 src/vgaterminal.hpp delete mode 100644 tasking.cpp delete mode 100644 tasking.hpp delete mode 100644 textoutput.hpp delete mode 100644 vgaterminal.cpp delete mode 100644 vgaterminal.hpp diff --git a/.gitignore b/.gitignore index 540202a..afda4de 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ -*.bin *.iso -*.o *.sw* iso/boot/*.bin +out diff --git a/Makefile b/Makefile index 728ead6..2484913 100644 --- 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 index b74a7dc..0000000 --- a/acpi.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "textoutput.hpp" - -#include - -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(acpiRsdp); - } else if (acpiRsdpV2) { - term.write("ACPI v2 detected, treating as v1.\n"); - rsdp = reinterpret_cast(acpiRsdpV2); - } - - //if (rsdp) { - // auto sdt = reinterpret_cast(rsdp->RsdtAddress); - //} -} - diff --git a/acpi.hpp b/acpi.hpp deleted file mode 100644 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 index e69de29..0000000 diff --git a/ata.hpp b/ata.hpp deleted file mode 100644 index 5394c31..0000000 --- a/ata.hpp +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef ATA_HPP -#define ATA_HPP - -#include "portio.hpp" - -#include -#include - -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 - struct Bus - { - template - using BPort = Port; - - [[no_unique_address]] BPort data; - [[no_unique_address]] BPort errFeats; - [[no_unique_address]] BPort count; - [[no_unique_address]] BPort lba0; - [[no_unique_address]] BPort lba1; - [[no_unique_address]] BPort lba2; - [[no_unique_address]] BPort select; - [[no_unique_address]] BPort 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 index 6b1da6a..0000000 --- a/boot.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include - -extern void (*__init_array_start)(); -extern void (*__init_array_end)(); -extern void kernel_main(); - -alignas(16) -static std::array 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 index 64a9e48..0000000 --- a/circularbuffer.hpp +++ /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 -#include -#include -#include -#include -#include - - -template -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 struct BufferIterator; - - -public: - typedef T value_type; - - // clyne - constexpr CircularBuffer() - :_buff{}, _max_size{0} {} - - explicit CircularBuffer(size_t size) - :_buff{std::unique_ptr(new value_type[size])}, _max_size{size}{} - - CircularBuffer(const CircularBuffer& other) - :_buff{std::unique_ptr(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 iterator; - typedef BufferIterator 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 _buff; - size_type _head = 0; - size_type _tail = 0; - size_type _size = 0; - size_type _max_size = 0; - - template - struct BufferIterator{ - public: - friend class CircularBuffer; - typedef std::random_access_iterator_tag iterator_category; - typedef ptrdiff_t difference_type; - typedef T value_type; - typedef typename std::conditional::type reference; - typedef typename std::conditional::type pointer; - typedef typename std::conditional*, - CircularBuffer*>::type cbuf_pointer; - private: - cbuf_pointer _ptrToBuffer; - size_type _offset; - size_type _index; - bool _reverse; - - bool _comparable(const BufferIterator& other) const{ - return (_ptrToBuffer == other._ptrToBuffer)&&(_reverse == other._reverse); - } - - public: - BufferIterator() - :_ptrToBuffer{nullptr}, _offset{0}, _index{0}, _reverse{false}{} - - BufferIterator(const BufferIterator& 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 -inline -bool CircularBuffer::full() const{ - return _size == _max_size; -} - -template -inline -bool CircularBuffer::empty() const{ - return _size == 0; -} - -template -inline -typename CircularBuffer::size_type CircularBuffer::capacity() const{ - return _max_size; -} - -template -inline -void CircularBuffer::clear(){ - //std::lock_guard _lck(_mtx); - _head = _tail = _size = 0; -} - -template -inline -typename CircularBuffer::size_type CircularBuffer::size() const{ - //std::lock_guard _lck(_mtx); - return _size; - } - -template -inline -typename CircularBuffer::reference CircularBuffer::front() { - //std::lock_guard _lck(_mtx); - // clyne - if(empty()) - abort(); //throw std::length_error("front function called on empty buffer"); - return _buff[_tail]; -} - -template -inline -typename CircularBuffer::reference CircularBuffer::back() { - //std::lock_guard _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 -inline -typename CircularBuffer::const_reference CircularBuffer::front() const{ - //std::lock_guard _lck(_mtx); - if(empty()) - abort(); //throw std::length_error("front function called on empty buffer"); - return _buff[_tail]; -} - -template -inline -typename CircularBuffer::const_reference CircularBuffer::back() const{ - //std::lock_guard _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 -inline -void CircularBuffer::push_back(const T& data){ - //std::lock_guard _lck(_mtx); - //if(full()) - // _buff[_tail].~T(); - _buff[_head] = data; - _increment_bufferstate(); -} - -template -inline -void CircularBuffer::push_back(T&& data) noexcept{ - //std::lock_guard _lck(_mtx); - _buff[_head] = std::move(data); - _increment_bufferstate(); -} - - -template -inline -void CircularBuffer::_increment_bufferstate(){ - if(full()) - _tail = (_tail + 1)%_max_size; - else - ++_size; - _head = (_head + 1)%_max_size; -} - -template -inline -void CircularBuffer::pop_front(){ - //std::lock_guard _lck(_mtx); - if(empty()) - abort(); //throw std::length_error("pop_front called on empty buffer"); - _decrement_bufferstate(); -} - -template -inline -void CircularBuffer::_decrement_bufferstate(){ - --_size; - _tail = (_tail + 1)%_max_size; -} - -template -inline -typename CircularBuffer::reference CircularBuffer::operator[](size_t index) { - //std::lock_guard _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 -inline -typename CircularBuffer::const_reference CircularBuffer::operator[](size_t index) const { - //std::lock_guard _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 -inline -typename CircularBuffer::reference CircularBuffer::at(size_t index) { - //std::lock_guard _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 -inline -typename CircularBuffer::const_reference CircularBuffer::at(size_t index) const { - //std::lock_guard _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 -inline -typename CircularBuffer::iterator CircularBuffer::begin() { - //std::lock_guard _lck(_mtx); - iterator iter; - iter._ptrToBuffer = this; - iter._offset = _tail; - iter._index = 0; - iter._reverse = false; - return iter; -} - -template -inline -typename CircularBuffer::const_iterator CircularBuffer::begin() const{ - //std::lock_guard _lck(_mtx); - const_iterator iter; - iter._ptrToBuffer = this; - iter._offset = _tail; - iter._index = 0; - iter._reverse = false; - return iter; -} - -template -inline -typename CircularBuffer::iterator CircularBuffer::end() { - //std::lock_guard _lck(_mtx); - iterator iter; - iter._ptrToBuffer = this; - iter._offset = _tail; - iter._index = _size; - iter._reverse = false; - return iter; -} - -template -inline -typename CircularBuffer::const_iterator CircularBuffer::end() const{ - //std::lock_guard _lck(_mtx); - const_iterator iter; - iter._ptrToBuffer = this; - iter._offset = _tail; - iter._index = _size; - iter._reverse = false; - return iter; -} - -template -inline -typename CircularBuffer::const_iterator CircularBuffer::cbegin() const noexcept{ - //std::lock_guard _lck(_mtx); - const_iterator iter; - iter._ptrToBuffer = this; - iter._offset = _tail; - iter._index = 0; - iter._reverse = false; - return iter; -} - -template -inline -typename CircularBuffer::const_iterator CircularBuffer::cend() const noexcept{ - //std::lock_guard _lck(_mtx); - const_iterator iter; - iter._ptrToBuffer = this; - iter._offset = _tail; - iter._index = _size; - iter._reverse = false; - return iter; -} - -template -inline -typename CircularBuffer::iterator CircularBuffer::rbegin() noexcept{ - //std::lock_guard _lck(_mtx); - iterator iter; - iter._ptrToBuffer = this; - iter._offset = _tail; - iter._index = 0; - iter._reverse = true; - return iter; -} - -template -inline -typename CircularBuffer::const_iterator CircularBuffer::rbegin() const noexcept{ - //std::lock_guard _lck(_mtx); - const_iterator iter; - iter._ptrToBuffer = this; - iter._offset = _tail; - iter._index = 0; - iter._reverse = true; - return iter; -} - -template -inline -typename CircularBuffer::iterator CircularBuffer::rend() noexcept{ - //std::lock_guard _lck(_mtx); - iterator iter; - iter._ptrToBuffer = this; - iter._offset = _tail; - iter._index = _size; - iter._reverse = true; - return iter; -} - -template -inline -typename CircularBuffer::const_iterator CircularBuffer::rend() const noexcept{ - //std::lock_guard _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 index 24d974b..0000000 --- a/gdt.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include -#include - -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 {{ - {}, - /* 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(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 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 index 5380c9e..0000000 --- a/idt.cpp +++ /dev/null @@ -1,126 +0,0 @@ -#include "idt.hpp" -#include "portio.hpp" -#include "textoutput.hpp" - -#include -#include -#include - -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 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 -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::index_sequence) { - return std::array { StubEntry()... }; - }(std::make_index_sequence{}); - -void idt_initialize() -{ - idt[0x28].dpl = 3; - - auto idtr = reinterpret_cast(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 index c5e7e47..0000000 --- a/idt.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef IDT_HPP -#define IDT_HPP - -#include -#include - -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 index ae3f153..0000000 --- a/kernel.cpp +++ /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 bus0; - ATA::Bus 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(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 index 48dad02..0000000 --- a/keyboard.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "circularbuffer.hpp" -#include "idt.hpp" -#include "keyboard.hpp" -#include "portio.hpp" -#include "vgaterminal.hpp" - -#include -#include - -extern TextOutput& term; - -static CircularBuffer keyboardBuffer; -static Port<0x60> keyboardPort; - -static const std::array 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(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 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 index 694ff89..0000000 --- a/keyboard.hpp +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef KEYBOARD_HPP -#define KEYBOARD_HPP - -#include - -#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 keyboard_read(); - -#endif // KEYBOARD_HPP - diff --git a/memmove.cpp b/memmove.cpp deleted file mode 100644 index 06e37df..0000000 --- a/memmove.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* Taken from newlib... */ - -#include -#include -#include - -/* 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(dst_void); - const char *src = reinterpret_cast(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 index 108c240..0000000 --- a/memory.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "textoutput.hpp" - -#include -#include - -struct PageDirectory -{ - static constexpr std::uint32_t NotPresent = 0x2; - - PageDirectory(): value(NotPresent) {} - PageDirectory(void *addr): value(reinterpret_cast(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; - -alignas(4096) -static std::array 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(lowerFree); - lowerFree += size; - lowerMem -= size; - } else if (upperMem > size) { - ret = reinterpret_cast(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 index 0467bf6..0000000 --- a/memory.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef MEMORY_HPP -#define MEMORY_HPP - -#include -#include - -template -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 - struct rebind { - typedef kallocator other; - }; - - kallocator() = default; - - template - kallocator(const kallocator&) 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 index 46c505b..0000000 --- a/multiboot.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "textoutput.hpp" - -#include - -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 -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(ptr); - next += ptr[1]; - next = (next + 7) & ~7; - ptr = reinterpret_cast(next); - } - - term.write('\n'); - return true; -} - diff --git a/multiboot.hpp b/multiboot.hpp deleted file mode 100644 index 9916850..0000000 --- a/multiboot.hpp +++ /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 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 index 17abd55..0000000 --- a/pic.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef PIC_HPP -#define PIC_HPP - -#include - -/* 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 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(end - ticks) > 0) - asm volatile("nop"); -} - diff --git a/pit.hpp b/pit.hpp deleted file mode 100644 index 55bcde9..0000000 --- a/pit.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef PIT_HPP -#define PIT_HPP - -#include - -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 index 7636c14..0000000 --- a/portio.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef PORTIO_HPP -#define PORTIO_HPP - -#include - -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 -struct Port -{ - Port() = default; - - template - 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 - operator T() const noexcept { - if constexpr (sizeof(T) == 1) - return inb(Addr); - else if constexpr (sizeof(T) == 2) - return inw(Addr); - } - - template - bool operator==(T val) const noexcept { - T dat = *this; - return dat == val; - } - - template - 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 index 0000000..b74a7dc --- /dev/null +++ b/src/acpi.cpp @@ -0,0 +1,51 @@ +#include "textoutput.hpp" + +#include + +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(acpiRsdp); + } else if (acpiRsdpV2) { + term.write("ACPI v2 detected, treating as v1.\n"); + rsdp = reinterpret_cast(acpiRsdpV2); + } + + //if (rsdp) { + // auto sdt = reinterpret_cast(rsdp->RsdtAddress); + //} +} + diff --git a/src/acpi.hpp b/src/acpi.hpp new file mode 100644 index 0000000..8154b81 --- /dev/null +++ b/src/acpi.hpp @@ -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 index 0000000..e69de29 diff --git a/src/ata.hpp b/src/ata.hpp new file mode 100644 index 0000000..5394c31 --- /dev/null +++ b/src/ata.hpp @@ -0,0 +1,131 @@ +#ifndef ATA_HPP +#define ATA_HPP + +#include "portio.hpp" + +#include +#include + +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 + struct Bus + { + template + using BPort = Port; + + [[no_unique_address]] BPort data; + [[no_unique_address]] BPort errFeats; + [[no_unique_address]] BPort count; + [[no_unique_address]] BPort lba0; + [[no_unique_address]] BPort lba1; + [[no_unique_address]] BPort lba2; + [[no_unique_address]] BPort select; + [[no_unique_address]] BPort 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 index 0000000..6b1da6a --- /dev/null +++ b/src/boot.cpp @@ -0,0 +1,36 @@ +#include +#include +#include + +extern void (*__init_array_start)(); +extern void (*__init_array_end)(); +extern void kernel_main(); + +alignas(16) +static std::array 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 index 0000000..64a9e48 --- /dev/null +++ b/src/circularbuffer.hpp @@ -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 +#include +#include +#include +#include +#include + + +template +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 struct BufferIterator; + + +public: + typedef T value_type; + + // clyne + constexpr CircularBuffer() + :_buff{}, _max_size{0} {} + + explicit CircularBuffer(size_t size) + :_buff{std::unique_ptr(new value_type[size])}, _max_size{size}{} + + CircularBuffer(const CircularBuffer& other) + :_buff{std::unique_ptr(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 iterator; + typedef BufferIterator 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 _buff; + size_type _head = 0; + size_type _tail = 0; + size_type _size = 0; + size_type _max_size = 0; + + template + struct BufferIterator{ + public: + friend class CircularBuffer; + typedef std::random_access_iterator_tag iterator_category; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef typename std::conditional::type reference; + typedef typename std::conditional::type pointer; + typedef typename std::conditional*, + CircularBuffer*>::type cbuf_pointer; + private: + cbuf_pointer _ptrToBuffer; + size_type _offset; + size_type _index; + bool _reverse; + + bool _comparable(const BufferIterator& other) const{ + return (_ptrToBuffer == other._ptrToBuffer)&&(_reverse == other._reverse); + } + + public: + BufferIterator() + :_ptrToBuffer{nullptr}, _offset{0}, _index{0}, _reverse{false}{} + + BufferIterator(const BufferIterator& 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 +inline +bool CircularBuffer::full() const{ + return _size == _max_size; +} + +template +inline +bool CircularBuffer::empty() const{ + return _size == 0; +} + +template +inline +typename CircularBuffer::size_type CircularBuffer::capacity() const{ + return _max_size; +} + +template +inline +void CircularBuffer::clear(){ + //std::lock_guard _lck(_mtx); + _head = _tail = _size = 0; +} + +template +inline +typename CircularBuffer::size_type CircularBuffer::size() const{ + //std::lock_guard _lck(_mtx); + return _size; + } + +template +inline +typename CircularBuffer::reference CircularBuffer::front() { + //std::lock_guard _lck(_mtx); + // clyne + if(empty()) + abort(); //throw std::length_error("front function called on empty buffer"); + return _buff[_tail]; +} + +template +inline +typename CircularBuffer::reference CircularBuffer::back() { + //std::lock_guard _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 +inline +typename CircularBuffer::const_reference CircularBuffer::front() const{ + //std::lock_guard _lck(_mtx); + if(empty()) + abort(); //throw std::length_error("front function called on empty buffer"); + return _buff[_tail]; +} + +template +inline +typename CircularBuffer::const_reference CircularBuffer::back() const{ + //std::lock_guard _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 +inline +void CircularBuffer::push_back(const T& data){ + //std::lock_guard _lck(_mtx); + //if(full()) + // _buff[_tail].~T(); + _buff[_head] = data; + _increment_bufferstate(); +} + +template +inline +void CircularBuffer::push_back(T&& data) noexcept{ + //std::lock_guard _lck(_mtx); + _buff[_head] = std::move(data); + _increment_bufferstate(); +} + + +template +inline +void CircularBuffer::_increment_bufferstate(){ + if(full()) + _tail = (_tail + 1)%_max_size; + else + ++_size; + _head = (_head + 1)%_max_size; +} + +template +inline +void CircularBuffer::pop_front(){ + //std::lock_guard _lck(_mtx); + if(empty()) + abort(); //throw std::length_error("pop_front called on empty buffer"); + _decrement_bufferstate(); +} + +template +inline +void CircularBuffer::_decrement_bufferstate(){ + --_size; + _tail = (_tail + 1)%_max_size; +} + +template +inline +typename CircularBuffer::reference CircularBuffer::operator[](size_t index) { + //std::lock_guard _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 +inline +typename CircularBuffer::const_reference CircularBuffer::operator[](size_t index) const { + //std::lock_guard _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 +inline +typename CircularBuffer::reference CircularBuffer::at(size_t index) { + //std::lock_guard _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 +inline +typename CircularBuffer::const_reference CircularBuffer::at(size_t index) const { + //std::lock_guard _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 +inline +typename CircularBuffer::iterator CircularBuffer::begin() { + //std::lock_guard _lck(_mtx); + iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::begin() const{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::iterator CircularBuffer::end() { + //std::lock_guard _lck(_mtx); + iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = _size; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::end() const{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = _size; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::cbegin() const noexcept{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::cend() const noexcept{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = _size; + iter._reverse = false; + return iter; +} + +template +inline +typename CircularBuffer::iterator CircularBuffer::rbegin() noexcept{ + //std::lock_guard _lck(_mtx); + iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = true; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::rbegin() const noexcept{ + //std::lock_guard _lck(_mtx); + const_iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = 0; + iter._reverse = true; + return iter; +} + +template +inline +typename CircularBuffer::iterator CircularBuffer::rend() noexcept{ + //std::lock_guard _lck(_mtx); + iterator iter; + iter._ptrToBuffer = this; + iter._offset = _tail; + iter._index = _size; + iter._reverse = true; + return iter; +} + +template +inline +typename CircularBuffer::const_iterator CircularBuffer::rend() const noexcept{ + //std::lock_guard _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 index 0000000..24d974b --- /dev/null +++ b/src/gdt.cpp @@ -0,0 +1,169 @@ +#include +#include + +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 {{ + {}, + /* 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(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 index 0000000..de5e8fc --- /dev/null +++ b/src/gdt.hpp @@ -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 index 0000000..5380c9e --- /dev/null +++ b/src/idt.cpp @@ -0,0 +1,126 @@ +#include "idt.hpp" +#include "portio.hpp" +#include "textoutput.hpp" + +#include +#include +#include + +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 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 +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::index_sequence) { + return std::array { StubEntry()... }; + }(std::make_index_sequence{}); + +void idt_initialize() +{ + idt[0x28].dpl = 3; + + auto idtr = reinterpret_cast(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 index 0000000..c5e7e47 --- /dev/null +++ b/src/idt.hpp @@ -0,0 +1,22 @@ +#ifndef IDT_HPP +#define IDT_HPP + +#include +#include + +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 index 0000000..ae3f153 --- /dev/null +++ b/src/kernel.cpp @@ -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 bus0; + ATA::Bus 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(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 index 0000000..48dad02 --- /dev/null +++ b/src/keyboard.cpp @@ -0,0 +1,64 @@ +#include "circularbuffer.hpp" +#include "idt.hpp" +#include "keyboard.hpp" +#include "portio.hpp" +#include "vgaterminal.hpp" + +#include +#include + +extern TextOutput& term; + +static CircularBuffer keyboardBuffer; +static Port<0x60> keyboardPort; + +static const std::array 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(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 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 index 0000000..694ff89 --- /dev/null +++ b/src/keyboard.hpp @@ -0,0 +1,32 @@ +#ifndef KEYBOARD_HPP +#define KEYBOARD_HPP + +#include + +#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 keyboard_read(); + +#endif // KEYBOARD_HPP + diff --git a/src/memmove.cpp b/src/memmove.cpp new file mode 100644 index 0000000..06e37df --- /dev/null +++ b/src/memmove.cpp @@ -0,0 +1,78 @@ +/* Taken from newlib... */ + +#include +#include +#include + +/* 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(dst_void); + const char *src = reinterpret_cast(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 index 0000000..108c240 --- /dev/null +++ b/src/memory.cpp @@ -0,0 +1,107 @@ +#include "textoutput.hpp" + +#include +#include + +struct PageDirectory +{ + static constexpr std::uint32_t NotPresent = 0x2; + + PageDirectory(): value(NotPresent) {} + PageDirectory(void *addr): value(reinterpret_cast(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; + +alignas(4096) +static std::array 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(lowerFree); + lowerFree += size; + lowerMem -= size; + } else if (upperMem > size) { + ret = reinterpret_cast(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 index 0000000..0467bf6 --- /dev/null +++ b/src/memory.hpp @@ -0,0 +1,38 @@ +#ifndef MEMORY_HPP +#define MEMORY_HPP + +#include +#include + +template +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 + struct rebind { + typedef kallocator other; + }; + + kallocator() = default; + + template + kallocator(const kallocator&) 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 index 0000000..46c505b --- /dev/null +++ b/src/multiboot.cpp @@ -0,0 +1,92 @@ +#include "textoutput.hpp" + +#include + +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 +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(ptr); + next += ptr[1]; + next = (next + 7) & ~7; + ptr = reinterpret_cast(next); + } + + term.write('\n'); + return true; +} + diff --git a/src/multiboot.hpp b/src/multiboot.hpp new file mode 100644 index 0000000..9916850 --- /dev/null +++ b/src/multiboot.hpp @@ -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 index 0000000..437f384 --- /dev/null +++ b/src/pic.cpp @@ -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 index 0000000..17abd55 --- /dev/null +++ b/src/pic.hpp @@ -0,0 +1,12 @@ +#ifndef PIC_HPP +#define PIC_HPP + +#include + +/* 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 index 0000000..964522b --- /dev/null +++ b/src/pit.cpp @@ -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(end - ticks) > 0) + asm volatile("nop"); +} + diff --git a/src/pit.hpp b/src/pit.hpp new file mode 100644 index 0000000..55bcde9 --- /dev/null +++ b/src/pit.hpp @@ -0,0 +1,10 @@ +#ifndef PIT_HPP +#define PIT_HPP + +#include + +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 index 0000000..7636c14 --- /dev/null +++ b/src/portio.hpp @@ -0,0 +1,72 @@ +#ifndef PORTIO_HPP +#define PORTIO_HPP + +#include + +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 +struct Port +{ + Port() = default; + + template + 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 + operator T() const noexcept { + if constexpr (sizeof(T) == 1) + return inb(Addr); + else if constexpr (sizeof(T) == 2) + return inw(Addr); + } + + template + bool operator==(T val) const noexcept { + T dat = *this; + return dat == val; + } + + template + 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 index 0000000..1b78011 --- /dev/null +++ b/src/tasking.cpp @@ -0,0 +1,92 @@ +#include "tasking.hpp" + +#include + +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 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(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(new std::uint8_t[ssize]); + const auto stackend = stack + ssize; + const auto regbase = stackend - sizeof(Registers); + auto r = reinterpret_cast(regbase); + r->ebp = stackend; + r->esp = stackend; + r->eip = reinterpret_cast(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 index 0000000..64a738e --- /dev/null +++ b/src/tasking.hpp @@ -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 index 0000000..7ef12fa --- /dev/null +++ b/src/textoutput.hpp @@ -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 index 0000000..5f86081 --- /dev/null +++ b/src/vgaterminal.cpp @@ -0,0 +1,63 @@ +#include "portio.hpp" +#include "vgaterminal.hpp" + +#include +#include +#include +#include + +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(Videoram); + ptr[offset++] = cell; +} + +void VGATerminal::checkpos() noexcept +{ + if (offset >= Width * Height) { + auto ptr = reinterpret_cast(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(offset)); + outb(0x03d4, 0x0e); + outb(0x03d5, static_cast(offset >> 8)); +} + diff --git a/src/vgaterminal.hpp b/src/vgaterminal.hpp new file mode 100644 index 0000000..9f8d5f3 --- /dev/null +++ b/src/vgaterminal.hpp @@ -0,0 +1,51 @@ +#ifndef VGATERMINAL_HPP +#define VGATERMINAL_HPP + +#include "textoutput.hpp" + +#include +#include + +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 index 1b78011..0000000 --- a/tasking.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "tasking.hpp" - -#include - -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 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(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(new std::uint8_t[ssize]); - const auto stackend = stack + ssize; - const auto regbase = stackend - sizeof(Registers); - auto r = reinterpret_cast(regbase); - r->ebp = stackend; - r->esp = stackend; - r->eip = reinterpret_cast(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 index 64a738e..0000000 --- a/tasking.hpp +++ /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 index 7ef12fa..0000000 --- a/textoutput.hpp +++ /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 index 5f86081..0000000 --- a/vgaterminal.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "portio.hpp" -#include "vgaterminal.hpp" - -#include -#include -#include -#include - -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(Videoram); - ptr[offset++] = cell; -} - -void VGATerminal::checkpos() noexcept -{ - if (offset >= Width * Height) { - auto ptr = reinterpret_cast(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(offset)); - outb(0x03d4, 0x0e); - outb(0x03d5, static_cast(offset >> 8)); -} - diff --git a/vgaterminal.hpp b/vgaterminal.hpp deleted file mode 100644 index 9f8d5f3..0000000 --- a/vgaterminal.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef VGATERMINAL_HPP -#define VGATERMINAL_HPP - -#include "textoutput.hpp" - -#include -#include - -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 - -- cgit v1.2.3