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