diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 50372c5..e6d5185 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ -bin/qkernel -bin/*.o -bin/*~ \ No newline at end of file +quark.iso +src/quark-kernel +src/interrupts/libinterrupts.a +*.o +*~ +rootfs/ +test/ \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d7cdb0d --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +.PHONY: all +all: quark.iso + +quark.iso: src/quark-kernel + cp src/quark-kernel rootfs/apps + grub-mkrescue -o $@ rootfs + +src/quark-kernel: + make -C src + +.PHONY: clean +clean: + make -C src clean + rm -f quark.iso diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/src/Makefile b/src/Makefile index 82cf391..e10855e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,16 +1,18 @@ -objs = math.o cstring.o error.o pagetableentry.o physicalmemoryallocator.o multiboot2header.o entry.o quarkkernel.o -link_script = linker.ld -quark_bin = qkernel +objs = addressspace.o tty.o buddyallocator.o math.o cstring.o pagetableentry.o multiboot2header.o systeminfo.o memorymap.o pio.o entry.o quarkkernel.o CXX = i686-elf-g++ CC = i686-elf-gcc -CPPFLAGS += -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti +CXXFLAGS = -ffreestanding -mgeneral-regs-only -O0 -Wall -fno-exceptions -fno-rtti -ggdb +LDFLAGS = -T linker.ld -lgcc -nostdlib -all: $(objs) - echo $(PATH) - i686-elf-g++ -o $(quark_bin) -T $(link_script) -ffreestanding -nostdlib -O2 $(objs) -lgcc +quark-kernel: $(objs) linker.ld interrupts/libinterrupts.a + $(CXX) -o $@ $(LDFLAGS) interrupts/libinterrupts.a $(objs) +interrupts/libinterrupts.a: + make -C interrupts CXX="$(CXX)" CC="$(CC)" CXXFLAGS="$(CXXFLAGS)" + +.PHONY: clean clean: - rm *.o - rm -f $(quark_bin) + make -C interrupts clean + rm -f $(objs) quark-kernel \ No newline at end of file diff --git a/src/addressspace.cpp b/src/addressspace.cpp new file mode 100644 index 0000000..8056e8a --- /dev/null +++ b/src/addressspace.cpp @@ -0,0 +1,51 @@ +#include "addressspace.hpp" + +kernel::AddressSpace::AddressSpace(MemoryAllocator& malloc) + : malloc(malloc) +{ + this->pageTables = (PageTableEntry*) 0xFFC00000; + this->pageDirectory = (PageTableEntry*) 0xFFFFF000; +} + +void* kernel::AddressSpace::mmap(void* start, size_t length) +{ + size_t tableIndex = (size_t) start / 4096; + for(int i = (int) length; i > 0; i -= 4096) + { + size_t directoryIndex = tableIndex / 1024; + if(!pageDirectory[directoryIndex].getPresent()) + { + physaddr_t newPT = malloc.allocate(4096); + pageDirectory[directoryIndex] = newPT; + pageDirectory[directoryIndex].setPresent(true); + pageDirectory[directoryIndex].setUsermode(false); + pageDirectory[directoryIndex].setRw(true); + } + if(!pageTables[tableIndex].getPresent()) + { + physaddr_t page = malloc.allocate(4096); + pageTables[tableIndex] = page; + pageTables[tableIndex].setUsermode(false); + pageTables[tableIndex].setRw(true); + pageTables[tableIndex].setPresent(true); + } + tableIndex++; + } + return start; +} + +void kernel::AddressSpace::munmap(void* start, size_t length) +{ + +} + +physaddr_t kernel::AddressSpace::getPhysicalAddress(void* virtualAddress) + const +{ + size_t index = (size_t) virtualAddress / 4096; + PageTableEntry pte = pageTables[index]; + if(pte.getPresent()) + return pte.getPhysicalAddress(); + else + return 0; +} diff --git a/src/addressspace.hpp b/src/addressspace.hpp new file mode 100755 index 0000000..b101cd2 --- /dev/null +++ b/src/addressspace.hpp @@ -0,0 +1,42 @@ +#ifndef SRC_ADDRESSSPACE_H_ +#define SRC_ADDRESSSPACE_H_ + +#include + +#include "memoryallocator.hpp" +#include "pagetableentry.hpp" +#include "systypes.hpp" + +namespace kernel { + +class AddressSpace { +public: + + AddressSpace(MemoryAllocator& malloc); + + void* mmap(void* start, size_t length); + + void munmap(void* start, size_t length); + + physaddr_t getPhysicalAddress(void* virtualAddress) const; + +private: + + MemoryAllocator& malloc; + + /** + * Array of 1024 page tables, each containing 1024 entries. + * The last table represents the page directory. + */ + PageTableEntry* pageTables; + + /** + * Array of 1024 PDEs, located at the end of the pageTables array + */ + PageTableEntry* pageDirectory; + +}; + +} /* namespace kernel */ + +#endif diff --git a/src/bitmap.h b/src/bitmap.h deleted file mode 100644 index 7e11b7b..0000000 --- a/src/bitmap.h +++ /dev/null @@ -1,609 +0,0 @@ -/* - * Bitmap.h - * - * Created on: Jun 1, 2019 - * Author: nathan - */ - -#ifndef SRC_BITMAP_H_ -#define SRC_BITMAP_H_ - -#include -#include -#include - -namespace qkernel { - -/** - * Represents a fixed array of N bits. Somewhat analogous to std::bitset. Can - * be manipulated using standard arithmetic operators (&, |, ^, ~). - */ -template -class Bitmap { -public: - - /** - * A proxy object used to reference an individual bit contained in a Bitmap object. - */ - class Reference - { - public: - - /** - * Construct a reference to a bit contained in a Bitmap object. - * - * @param data A reference to the byte in which the referenced bit is - * contained - * @param position The position of the referenced bit inside 'data.' 0 - * denotes the least significant bit; 7 denoted the most significant - * bit. - */ - Reference(uint8_t& data, size_t position); - - /** - * Sets the bit referenced by this object to 'b' - * - * @returns a reference to this object - */ - Reference& operator=(const bool b); - - /** - * Sets the bit referenced by this object to the value of the bit - * referenced by 'r.' - * - * @returns a reference to this object - */ - Reference& operator=(const Reference& r); - - /** - * @returns the inverse of the value of the bit referenced by this - * object. - */ - bool operator~() const; - - /** - * Converts the bit referenced by this object to a boolean, whose value - * is 'true' if the bit referenced it set, and false if it is clear. - */ - operator bool() const; - - private: - - uint8_t& data; - - size_t position; - - }; - - /** - * Constructs a bitmap containing 'N' bits, containing uninitialized - * data. - */ - Bitmap(); - - /** - * Constructs a bitmap containing 'N' bits, copying data from 'bitmap' into - * the new object. - */ - Bitmap(const Bitmap& bitmap); - - /** - * Constructs a bitmap containing 'N' bits, initializing each bit to 'v.' - */ - Bitmap(const bool value); - - /** - * Constructs a bitmap containing 'N' bits, initializing the first 32 bits - * to the bits contained in 'value.' If the bitmap contains more than 32 - * bits, the rest are initialized to 0. - */ - Bitmap(const uint8_t value); - - /** - * Constructs a bitmap containing 'N' bits, initializing the first 32 bits - * to the bits contained in 'value.' If the bitmap contains more than 32 - * bits, the rest are initialized to 0. - */ - Bitmap(const uint16_t value); - - /** - * Constructs a bitmap containing 'N' bits, initializing the first 32 bits - * to the bits contained in 'value.' If the bitmap contains more than 32 - * bits, the rest are initialized to 0. - */ - Bitmap(const uint32_t value); - - /** - * @returns the number of bits stored in this bitmap - */ - size_t size(); - - /** - * @returns the number of bits that are set - */ - size_t count(); - - /** - * @returns true if all bits are set; otherwise false. - */ - bool all(); - - /** - * @returns true if at least one bit is set; otherwise false. - */ - bool any(); - - /** - * @returns true if all bits are cleared; otherwise false. - */ - bool none(); - - /** - * Sets all bits in this bitmap. - * - * @returns a reference to this bitmap - */ - Bitmap& set(); - - /** - * Clears all bits in this bitmap. - * - * @returns a reference to this bitmap - */ - Bitmap& clear(); - - /** - * Compares the contents of 'bitmap' and this bitmap. - * - * @param bitmap The bitmap to compare this object to. - * - * @returns true only if each bit in 'other' is equal to each bit in this - * bitmap; otherwise false. - */ - bool operator==(const Bitmap& other) const; - - /** - * Compares the contents of 'bitmap' and this bitmap. - * - * @param bitmap The bitmap to compare this object to. - * - * @returns false only if each bit in 'other' is equal to each bit in this - * bitmap; otherwise true. - */ - bool operator!=(const Bitmap& other) const; - - /** - * Accesses the bit at 'index.' Does not perform bounds checking; - * out-of-bounds access will result in problems. - * - * @param index The position in the bitmap to access - * - * @returns a reference to the bit at 'index' - */ - Reference operator[](const size_t index); - - /** - * Accesses the bit at 'index.' Does not perform bounds checking; - * out-of-bounds access will result in problems. - * - * @param index The position in the bitmap to access - * - * @returns the value of the bit at position 'index' - */ - bool operator[](const size_t index) const; - - /** - * @returns a bitmap containing the bitwise AND of this bitmap and 'other.' - */ - Bitmap operator&(const Bitmap& other) const; - - /** - * Sets the value of this bitmap to the bitwise AND of this bitmap and - * 'other.' - * - * @returns a reference to this bitmap - */ - Bitmap& operator&=(const Bitmap& other); - - /** - * @returns a bitmap containing the bitwise OR of this bitmap and 'other.' - */ - Bitmap operator|(const Bitmap& other) const; - - /** - * Sets the value of this bitmap to the bitwise OR of this bitmap and - * 'other.' - * - * @returns a reference to this bitmap - */ - Bitmap& operator|=(const Bitmap& other); - - /** - * @returns a bitmap containing the bitwise XOR of this bitmap and 'other.' - */ - Bitmap operator^(const Bitmap& other) const; - - /** - * Sets the value of this bitmap to the bitwise OR of this bitmap and - * 'other.' - * - * @returns a reference to this bitmap - */ - Bitmap& operator^=(const Bitmap& other); - - /** - * Shifts this bitmap 'n' bits left. - * - * @returns a new Bitmap containing the result - */ - Bitmap operator<<(const size_t n) const; - - /** - * Shifts this bitmap 'n' bits left. - * - * @returns a reference to this bitmap - */ - Bitmap& operator<<=(const size_t n); - - /** - * Shifts this bitmap 'n' bits right. - * - * @returns a new Bitmap containing the result - */ - Bitmap operator>>(const size_t n) const; - - /** - * Shifts the bitmap 'n' bits right. - * - * @returns a reference to this bitmap - */ - Bitmap& operator>>=(const size_t n); - - /** - * Computes the bitwise NOT of this bitmap - * - * @returns a new bitmap containing the result - */ - Bitmap operator~() const; - -private: - - uint8_t data[(N / 8) + 1]; - -}; - -} /* namespace qkernel */ - -template -inline qkernel::Bitmap::Reference::Reference(uint8_t& data, size_t position) - : data(data) -{ - this->position = position; -} - -template -inline typename qkernel::Bitmap::Reference& qkernel::Bitmap::Reference::operator =(const bool b) { - if(b) - { - data |= 1 << position; - } - else - { - data &= ~(1 << position); - } - return *this; -} - -template -inline typename qkernel::Bitmap::Reference& qkernel::Bitmap::Reference::operator =(const Reference& r) { - if((bool) r) - { - data |= 1 << position; - } - else - { - data &= ~(1 << position); - } -} - -template -inline bool qkernel::Bitmap::Reference::operator ~() const { - return !((bool) (*this)); -} - -template -inline qkernel::Bitmap::Reference::operator bool() const { - uint8_t value = data & (1 << position); - if((data & (1 << position)) != 0) - { - return true; - } - else - { - return false; - } -} - -template -inline qkernel::Bitmap::Bitmap() { -} - -template -inline qkernel::Bitmap::Bitmap(const Bitmap& bitmap) { - for(size_t i = 0; i < N; i++) - { - (*this)[i] = bitmap[i]; - } -} - -template -inline qkernel::Bitmap::Bitmap(const bool value) { - for(size_t i = 0; i < N; i++) - { - (*this)[i] = value; - } -} - -template -inline qkernel::Bitmap::Bitmap(uint8_t value) { - size_t max = N >= 8 ? 8 : N; - for(size_t i = 0; i < max; i++) - { - (*this)[i] = value & 1; - value >>= 1; - } -} - -template -inline qkernel::Bitmap::Bitmap(uint16_t value) { - size_t max = N >= 16 ? 16 : N; - for(size_t i = 0; i < max; i++) - { - (*this)[i] = value & 1; - value >>= 1; - } -} - -template -inline qkernel::Bitmap::Bitmap(uint32_t value) { - size_t max = N >= 32 ? 32 : N; - for(size_t i = 0; i < max; i++) - { - (*this)[i] = value & 1; - value >>= 1; - } -} - -template -inline size_t qkernel::Bitmap::size() { - return N; -} - -template -inline size_t qkernel::Bitmap::count() { - size_t count = 0; - for(size_t i = 0; i < N; i++) - { - if((*this)[i] == true) - { - count++; - } - } - return count; -} - -template -inline bool qkernel::Bitmap::all() { - for(size_t i = 0; i < N; i++) - { - if((*this)[i] == false) - { - return false; - } - } - return true; -} - -template -inline bool qkernel::Bitmap::any() { - for(size_t i = 0; i < N; i++) - { - if((*this)[i] == true) - { - return true; - } - } - return false; -} - -template -inline bool qkernel::Bitmap::none() { - for(size_t i = 0; i < N; i++) - { - if((*this)[i] == true) - { - return false; - } - } - return true; -} - -template -inline qkernel::Bitmap& qkernel::Bitmap::set() { - for(size_t i = 0; i < N; i++) - { - (*this)[i] = true; - } - return *this; -} - -template -inline qkernel::Bitmap& qkernel::Bitmap::clear() { - for(size_t i = 0; i < N; i++) - { - (*this)[i] = false; - } - return *this; -} - -template -inline bool qkernel::Bitmap::operator ==(const Bitmap& other) const { - for(size_t i = 0; i < N; i++) - { - if((*this)[i] != other[i]) - { - return false; - } - } - return true; -} - -template -inline bool qkernel::Bitmap::operator !=(const Bitmap& other) const { - return !((*this) == other); -} - -template -inline typename qkernel::Bitmap::Reference qkernel::Bitmap::operator [](const size_t index) { - return Reference(data[index / 8], index % 8); -} - -template -inline bool qkernel::Bitmap::operator [](const size_t index) const { - return (data[index/8] & (1 << (index % 8))) == 0 ? false : true; -} - -template -inline qkernel::Bitmap qkernel::Bitmap::operator &(const Bitmap& other) const { - Bitmap result; - for(size_t i = 0; i < N; i++) - { - result[i] = (*this)[i] && other[i]; - } - return result; -} - -template -inline qkernel::Bitmap& qkernel::Bitmap::operator &=(const Bitmap& other) { - for(size_t i = 0; i < N; i++) - { - (*this)[i] = (*this)[i] && other[i]; - } - return *this; -} - -template -inline qkernel::Bitmap qkernel::Bitmap::operator |(const Bitmap& other) const { - Bitmap result; - for(size_t i = 0; i < N; i++) - { - result[i] = (*this)[i] || other[i]; - } - return result; -} - -template -inline qkernel::Bitmap& qkernel::Bitmap::operator |=(const Bitmap& other) { - for(size_t i = 0; i < N; i++) - { - (*this)[i] = (*this)[i] || other[i]; - } - return *this; -} - -template -inline qkernel::Bitmap qkernel::Bitmap::operator ^(const Bitmap& other) const { - Bitmap result; - for(size_t i = 0; i < N; i++) - { - result[i] = (*this)[i] ^ other[i]; - } - return result; -} - -template -inline qkernel::Bitmap& qkernel::Bitmap::operator ^=(const Bitmap& other) { - for(size_t i = 0; i < N; i++) - { - (*this)[i] = (*this)[i] ^ other[i]; - } - return *this; -} - -template -inline qkernel::Bitmap qkernel::Bitmap::operator <<(const size_t n) const { - Bitmap result; - for(size_t i = 0; i < N; i++) - { - if(i < n) - { - result[i] = false; - } - else - { - result[i] = (*this)[i-n]; - } - } - return result; -} - -template -inline qkernel::Bitmap& qkernel::Bitmap::operator <<=(const size_t n) { - for(size_t i = 0; i < N; i++) - { - if(i == 0) - { - (*this)[i] = 0; - } - else - { - (*this)[i] = (*this)[i-1]; - } - } - return *this; -} - -template -inline qkernel::Bitmap qkernel::Bitmap::operator >>(const size_t n) const { - Bitmap result; - for(size_t i = 0; i < N; i++) - { - if(i > N - n) - { - result[i] = false; - } - else - { - result[i] = (*this)[i+n]; - } - } - return result; -} - -template -inline qkernel::Bitmap& qkernel::Bitmap::operator >>=(const size_t n) { - for(size_t i = N - 1; i >= 0; i--) - { - if(i == N - 1) - { - (*this)[i] = 0; - } - else - { - (*this)[i] = (*this)[i+1]; - } - } - return *this; -} - -template -inline qkernel::Bitmap qkernel::Bitmap::operator ~() const { - Bitmap result; - for(size_t i = 0; i < N; i++) - { - result[i] = !(*this)[i]; - } - return result; -} - -#endif /* SRC_BITMAP_H_ */ diff --git a/src/buddyallocator.cpp b/src/buddyallocator.cpp new file mode 100755 index 0000000..c8f9f81 --- /dev/null +++ b/src/buddyallocator.cpp @@ -0,0 +1,253 @@ +#include "buddyallocator.hpp" +#include "math.h" +#include "systypes.hpp" +#include "memorymap.hpp" + +#define roundUp(n, m) ((n % m == 0) ? n : (n + m - (n % m))) + +kernel::BuddyAllocator::BuddyAllocator() +{ + +} + +kernel::BuddyAllocator::BuddyAllocator(kernel::MemoryMap& memmap, + char* bitmap, size_t blockCount, + size_t treeHeight) +{ + this->bitmap = bitmap; + this->blockSize = 4096; + this->blockCount = blockCount; + this->treeHeight = treeHeight; + for(size_t i = 0; i <= treeHeight; i++) + { + for(size_t j = 0; j < (blockCount >> i); j++) + { + reserveNode(i, j); + } + } + physaddr_t location = 0x100000; + for(size_t i = 0; i < memmap.size() && memmap[i].getSize() > 0; i++) + { + if(memmap[i].getType() != kernel::MemoryMap::AVAILABLE) + continue; + if(memmap[i].getLocation() > location) + location = roundUp(memmap[i].getLocation(), 4096); + while(memmap[i].contains(location, 4096)) + { + freeNode(0, location / 4096); + if(isFree(0, getBuddy(location / 4096))) + merge(0, location / 4096); + location += 4096; + } + } +} + +kernel::BuddyAllocator::BuddyAllocator(char* bitmap, size_t blockSize, + size_t blockCount, size_t treeHeight) +{ + this->bitmap = bitmap; + this->blockSize = blockSize; + this->blockCount = blockCount; + this->treeHeight = treeHeight; + for(size_t i = 0; i <= treeHeight; i++) + { + for(size_t j = 0; j < (blockCount >> i); j++) + { + if(i < treeHeight) + reserveNode(i, j); + else + freeNode(i, j); + } + } +} + +physaddr_t kernel::BuddyAllocator::allocate(size_t size) +{ + size_t height = ilog2(roundUp(size, blockSize) / blockSize, true); + if(height > treeHeight) // Requested block size is greater than maximum + { + return NULL; + } + else + { + size_t index = findFreeBlock(height); + if(index == INVALID) // Failed to find a big enough free block; out of memory + { + return NULL; + } + else + { + reserveNode(height, index); + return nodeToAddress(height, index); + } + } +} + +void kernel::BuddyAllocator::free(physaddr_t location, size_t size) +{ + size_t height = ilog2(roundUp(size, blockSize) / blockSize, true); + if(height <= treeHeight) + { + size_t index = addressToNode(height, location); + freeNode(height, index); + if(isFree(height, getBuddy(index))) + { + merge(height, index); + } + } +} + +size_t kernel::BuddyAllocator::freeBlocks() const +{ + size_t count = 0; + for(size_t j = 0; j < blockCount; j++) + { + if(isFree(0, j)) + { + count++; + } + } + return count; +} + +size_t kernel::BuddyAllocator::maxAllocationSize() const +{ + for(size_t i = treeHeight; i >= 0; i--) + { + for(size_t j = 0; j < (blockCount >> i); j++) + { + if(isFree(i, j)) + { + return 1 << i; + } + } + } + return 0; +} + +size_t kernel::BuddyAllocator::getBlockSize() const +{ + return blockSize; +} + +size_t kernel::BuddyAllocator::getMemorySize() const +{ + return blockCount; +} + +size_t kernel::BuddyAllocator::findFreeBlock(size_t height) +{ + for(size_t i = 0; i < (blockCount >> height); i++) + { + if(isFree(height, i)) + { + return i; + } + } + if(height < treeHeight) + { + size_t parentIndex = findFreeBlock(height + 1); + if(parentIndex != INVALID) + { + return split(height + 1, parentIndex); + } + } + return INVALID; +} + +size_t kernel::BuddyAllocator::split(size_t height, size_t index) +{ + if(height > 0 && isFree(height, index)) + { + reserveNode(height, index); + freeNode(height - 1, getChild(index)); + freeNode(height - 1, getBuddy(getChild(index))); + return getChild(index); + } + else + { + return INVALID; + } +} + +size_t kernel::BuddyAllocator::merge(size_t height, size_t index) +{ + if(isFree(height, index) && isFree(height, getBuddy(index)) && height < treeHeight) + { + reserveNode(height, index); + reserveNode(height, getBuddy(index)); + freeNode(height + 1, getParent(index)); + if((height + 1) < treeHeight) + { + if(isFree(height + 1, getBuddy(getParent(index)))) + { + return merge(height + 1, getParent(index)); + + } + } + return getParent(index); + } + else + { + return INVALID; + } +} + +size_t kernel::BuddyAllocator::getBuddy(size_t index) +{ + return index ^ 1; +} + +size_t kernel::BuddyAllocator::getParent(size_t index) +{ + return index / 2; +} + +size_t kernel::BuddyAllocator::getChild(size_t index) +{ + return index * 2; +} + +physaddr_t kernel::BuddyAllocator::nodeToAddress(size_t height, size_t index) + const +{ + return index * (blockSize << height); +} + +size_t kernel::BuddyAllocator::addressToNode(size_t height, + physaddr_t location) const +{ + return location / (blockSize << height); +} + +void kernel::BuddyAllocator::reserveNode(size_t height, size_t index) +{ + size_t bit = (height == 0) ? 0 + : ((blockCount * 2) - (blockCount >> (height - 1))); + bit += index; + bitmap[bit / 8] |= 1 << (bit % 8); +} + +void kernel::BuddyAllocator::freeNode(size_t height, size_t index) +{ + size_t bit = (height == 0) ? 0 + : ((blockCount * 2) - (blockCount >> (height - 1))); + bit += index; + bitmap[bit / 8] &= ~(1 << (bit % 8)); +} + +bool kernel::BuddyAllocator::isFree(size_t height, size_t index) const +{ + size_t bit = (height == 0) ? 0 + : ((blockCount * 2) - (blockCount >> (height - 1))); + bit += index; + char data = bitmap[bit / 8] & (1 << (bit % 8)); + if(data == 0) + { + return true; + } + else + { + return false; + } +} diff --git a/src/buddyallocator.hpp b/src/buddyallocator.hpp new file mode 100755 index 0000000..edee782 --- /dev/null +++ b/src/buddyallocator.hpp @@ -0,0 +1,94 @@ +#ifndef BUDDYALLOCATOR_H_ +#define BUDDYALLOCATOR_H_ + +#include "memoryallocator.hpp" +#include "memorymap.hpp" + +namespace kernel +{ + +class BuddyAllocator : public MemoryAllocator +{ +public: + + BuddyAllocator(); + + BuddyAllocator(MemoryMap& memmap, char* bitmap, size_t blockCount, + size_t treeHeight); + + BuddyAllocator(char* bitmap, size_t blockSize, size_t blockCount, + size_t treeHeight); + + /** + * Allocate a block of memory containing at least 'size' bytes. + * Rounds up to the nearest power of 2 times the size of a block. + */ + virtual physaddr_t allocate(size_t size); + + /** + * Free the region of memory starting at 'location' and containing + * 'size' bytes. + */ + virtual void free(physaddr_t location, size_t size); + + /** + * @returns the total number of free blocks of memory. + */ + virtual size_t freeBlocks() const; + + /** + * @returns the size in blocks of the largest possible allocation that + * will not fail due to lack of memory. + */ + virtual size_t maxAllocationSize() const; + + /** + * @returns the size in bytes of a single block. + */ + virtual size_t getBlockSize() const; + + /** + * @returns the total number of blocks managed by this memory + * allocator. + */ + virtual size_t getMemorySize() const; + +private: + + static const size_t INVALID = (size_t) -1; + + char* bitmap; + + size_t blockSize; + + size_t blockCount; + + size_t treeHeight; + + size_t findFreeBlock(size_t height); + + size_t split(size_t height, size_t index); + + size_t merge(size_t height, size_t index); + + size_t getBuddy(size_t index); + + size_t getParent(size_t index); + + size_t getChild(size_t index); + + physaddr_t nodeToAddress(size_t height, size_t index) const; + + size_t addressToNode(size_t height, physaddr_t location) const; + + void reserveNode(size_t height, size_t index); + + void freeNode(size_t height, size_t index); + + bool isFree(size_t height, size_t index) const; + +}; + +} + +#endif diff --git a/src/cstring.cpp b/src/cstring.cpp old mode 100644 new mode 100755 diff --git a/src/cstring.h b/src/cstring.h old mode 100644 new mode 100755 diff --git a/src/entry.S b/src/entry.S old mode 100644 new mode 100755 index b0dd842..2778259 --- a/src/entry.S +++ b/src/entry.S @@ -1,6 +1,28 @@ .section .multiboot .include "multiboot2header.S" +.section .rodata + +gdt: +.long 0, 0 +.short 0xFFFF +.short 0x0000 +.short 0x9A00 +.short 0x00CF +.short 0xFFFF +.short 0x0000 +.short 0x9200 +.short 0x00CF + +gdt_info: +.short 23 +.long gdt + +.align 16 +idt_info: +.short idt_end - idt - 1 +.long idt + .section .bss .align 16 @@ -14,8 +36,26 @@ _tempPgDir: _tempIdentityMap: .skip 4096 _tempPgTable: -.skip 4096 +.skip 8192 +_bootCmdLine: +.skip 64 + +.align 64 +.global system_info +system_info: +.skip 16 + +.align 64 +.global memory_map +memory_map: +.skip 16 * 16 + +.global idt +idt: +.skip 8 * 256 +idt_end: + .section .text .global _start .type _start, @function @@ -25,42 +65,172 @@ _start: movb $64, 0xB8000 + mov $system_info, %edi + sub $BASE_DIFF, %edi + add $8, %ebx + +switch: mov (%ebx), %eax + cmp $0, %eax + je s_end + cmp $1, %eax + je tag_1 + cmp $4, %eax + je tag_4 + cmp $6, %eax + je tag_6 + cmp $21, %eax + je tag_21 + jmp def + +# Boot command line +tag_1: mov 4(%ebx), %ecx + sub $8, %ecx + mov %ebx, %esi + add $8, %esi + mov $_bootCmdLine, %edi + sub $BASE_DIFF, %edi + rep movsb + mov $system_info, %edi + sub $BASE_DIFF, %edi + jmp def + +# Basic memory info +tag_4: mov 8(%ebx), %eax + mov %eax, (%edi) + mov 12(%ebx), %eax + mov %eax, 4(%edi) + jmp def + +# Memory map +tag_6: mov $memory_map, %esi + sub $BASE_DIFF, %esi # set esi to point to the table in the kernel image + mov 4(%ebx), %ecx + sub $16, %ecx # set ecx to store the size of the table provided by the bootloader + mov 8(%ebx), %edx # set edx to store the size of each table entry + add $16, %ebx # move ebx up to the first entry +1: mov (%ebx), %eax + mov %eax, (%esi) # save the address of that region in memory + mov 8(%ebx), %eax + mov %eax, 4(%esi) # save the size of that region in memory + mov 16(%ebx), %eax + mov %eax, 8(%esi) # save the type of memory in that region + add $12, %esi # move esi to the next entry in the kernel's array + add %edx, %ebx # move ebx to the next entry in the bootloader's array + sub %edx, %ecx # subtract the size of an entry from ecx. + jnz 1b # loop if there are entries left + mov $0, %eax + mov %eax, (%esi) + mov %eax, 4(%esi) + mov %eax, 8(%esi) + jmp switch + +# Program image location +tag_21: mov 8(%ebx), %eax + mov %eax, 8(%edi) + jmp def + +def: mov 4(%ebx), %eax + add $7, %eax + and $0xFFFFFFF8, %eax + add %eax, %ebx + jmp switch +s_end: + + movb $64, 0xB8002 + mov $0, %ecx -1: mov %ecx, %eax +1: + # Generate a page table entry pointing to a page in the kernel binary + mov %ecx, %eax mov $4096, %edx mul %edx - add $PHYSICAL_BASE, %eax or $3, %eax + + # Load the address of the temporary page table and translate it to a physical address mov $_tempPgTable, %edi + sub $BASE_DIFF, %edi + + # Save the PTE into an entry in the temporary page table mov %eax, (%edi, %ecx, 4) + + # Load the address of the identity map and translate it to a physical address mov $_tempIdentityMap, %edi - mov %eax, 1024(%edi, %ecx, 4) + sub $BASE_DIFF, %edi + + # Save the PTE into an entry in the identity map + mov %eax, (%edi, %ecx, 4) + + # Increment count and loop inc %ecx - cmp $IMAGE_SIZE, %ecx + mov $IMAGE_SIZE, %edx + add $256, %edx + cmp %edx, %ecx jne 1b + # Load the physical address of the identity map, and generate a PDE mov $_tempIdentityMap, %eax + sub $BASE_DIFF, %eax or $3, %eax - mov %eax, (_tempPgDir) + # Load the physical address of the page directory + mov $_tempPgDir, %edi + sub $BASE_DIFF, %edi + + # Save the PDE to the first element in the page directory + mov %eax, (%edi) + + # Load the physical address of the temporary page table, and generate a PDE mov $_tempPgTable, %eax + sub $BASE_DIFF, %eax or $3, %eax - mov %eax, (_tempPgDir + 3072) - mov $_tempPgDir, %eax - mov %eax, %cr3 + # Save the PDE to the entry corresponding to 0xC0000000 + mov %eax, 3072(%edi) + + # Set the last entry in the page directory to point to the page directory itself + mov %edi, %eax + or $3, %eax + mov %eax, 4092(%edi) + # Load the physical address of the page directory into CR3 + mov $_tempPgDir, %edi + sub $BASE_DIFF, %edi + mov %edi, %cr3 + + # Enable paging mov %cr0, %eax or $0x80010000, %eax mov %eax, %cr0 + + # Jump into mapped kernel binary lea 2f, %eax jmp *%eax -2: movl $0, (_tempIdentityMap) +2: + # Delete PDE corresponding to identity map. We shouldn't need it anymore. + movl $0, (_tempIdentityMap) + + # Reload page tables mov %cr3, %eax mov %eax, %cr3 + # Initialize stack mov $stackTop, %esp + lgdt gdt_info + lidt idt_info + jmp $8, $.ldcs +.ldcs: + mov $16, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %gs + mov %ax, %fs + mov %ax, %ss + + mov $_bootCmdLine, %eax + push %eax + + # Call main function call main _err: diff --git a/src/error.cpp b/src/error.cpp deleted file mode 100644 index b22ff75..0000000 --- a/src/error.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Error.cpp - * - * Created on: May 23, 2019 - * Author: nathan - */ - -#include "error.h" - -namespace qkernel { - -Error lastError; - -Error::Error() - : errorType(ErrorType::none), message("") {} - -Error::Error(ErrorType errorType) - : errorType(errorType), message("") {} - -Error::Error(ErrorType errorType, const char* message) - : errorType(errorType), message(message) {} - -ErrorType Error::getType() -{ - return errorType; -} - -const char* Error::getMessage() -{ - return message; -} - -} /* namespace qkernel */ diff --git a/src/error.h b/src/error.h deleted file mode 100644 index eeddde1..0000000 --- a/src/error.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Error.h - * - * Created on: May 23, 2019 - * Author: nathan - */ - -#ifndef SRC_ERROR_H_ -#define SRC_ERROR_H_ - -#include "errortype.h" - -namespace qkernel { - -class Error { -public: - - Error(); - - Error(ErrorType errorType); - - Error(ErrorType errorType, const char* message); - - ErrorType getType(); - - const char* getMessage(); - -private: - - ErrorType errorType; - - const char* message; - -}; - -extern Error lastError; - -} /* namespace qkernel */ - -#endif /* SRC_ERROR_H_ */ diff --git a/src/errortype.h b/src/errortype.h deleted file mode 100644 index e4307f6..0000000 --- a/src/errortype.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * ErrorType.h - * - * Created on: May 23, 2019 - * Author: nathan - */ - -#ifndef SRC_ERRORTYPE_H_ -#define SRC_ERRORTYPE_H_ - - -enum class ErrorType -{ - none, - outOfBounds, - illegalState, - outOfMemory, - invalidArgument -}; - - -#endif /* SRC_ERRORTYPE_H_ */ diff --git a/src/interrupts/Makefile b/src/interrupts/Makefile new file mode 100644 index 0000000..c818c6f --- /dev/null +++ b/src/interrupts/Makefile @@ -0,0 +1,9 @@ +objs = x86/inthandlers.o x86/interruptdescriptor.o x86/idt.o x86/interrupts.o +archive = libinterrupts.a + +$(archive): $(objs) + i686-elf-ar rcs $@ $^ + +.PHONY: clean +clean: + rm -f $(archive) $(objs) \ No newline at end of file diff --git a/src/interrupts/interrupts.hpp b/src/interrupts/interrupts.hpp new file mode 100644 index 0000000..173a002 --- /dev/null +++ b/src/interrupts/interrupts.hpp @@ -0,0 +1,19 @@ +#ifndef INTERRUPTS_H +#define INTERRUPTS_H + +namespace kernel +{ + class Interrupts + { + public: + + Interrupts(); + + void enable(); + + void disable(); + + }; +} + +#endif \ No newline at end of file diff --git a/src/interrupts/x86/idt.S b/src/interrupts/x86/idt.S new file mode 100644 index 0000000..a76f770 --- /dev/null +++ b/src/interrupts/x86/idt.S @@ -0,0 +1,21 @@ +.section .bss + +.align 8 +.global idt +idt: +.skip 8 * 256 +idt_end: + +.section .rodata + +.idt_info: +.short idt_end - idt - 1 +.long idt + +.section .text + +.global _lidt +.type _lidt, @function +_lidt: + + ret \ No newline at end of file diff --git a/src/interrupts/x86/idt.hpp b/src/interrupts/x86/idt.hpp new file mode 100644 index 0000000..2c1cf0f --- /dev/null +++ b/src/interrupts/x86/idt.hpp @@ -0,0 +1,10 @@ +#ifndef IDT_H +#define IDT_H + +#include "interruptdescriptor.hpp" + +extern kernel::InterruptDescriptor idt[256]; + +extern "C" void _lidt(); + +#endif \ No newline at end of file diff --git a/src/interrupts/x86/interruptdescriptor.cpp b/src/interrupts/x86/interruptdescriptor.cpp new file mode 100644 index 0000000..866bd6f --- /dev/null +++ b/src/interrupts/x86/interruptdescriptor.cpp @@ -0,0 +1,62 @@ +#include "interruptdescriptor.hpp" + +kernel::InterruptDescriptor::InterruptDescriptor() +{ + this->m_offset1 = 0; + this->m_selector = 0; + this->m_zero = 0; + this->m_type = 0; + this->m_storage = 0; + this->m_dpl = 0; + this->m_present = 0; + this->m_offset2 = 0; +} + +kernel::InterruptDescriptor::InterruptDescriptor(void* handler, Type type, unsigned int dpl) +{ + uint32_t offset = (uint32_t) handler; + this->m_offset1 = (uint16_t) offset; + this->m_selector = 8; + this->m_zero = 0; + this->m_type = (uint16_t) type; + this->m_storage = 0; + this->m_dpl = dpl; + this->m_present = 1; + this->m_offset2 = offset >> 16; +} + +bool kernel::InterruptDescriptor::present() +{ + return m_present == 1; +} +void kernel::InterruptDescriptor::present(bool present) +{ + m_present = present ? 1 : 0; +} + +kernel::InterruptDescriptor::Type kernel::InterruptDescriptor::type() +{ + return (Type) m_type; +} + +void kernel::InterruptDescriptor::type(kernel::InterruptDescriptor::Type type) +{ + m_type = (unsigned int) type; +} + +unsigned int kernel::InterruptDescriptor::dpl() +{ + return m_dpl; +} + +void kernel::InterruptDescriptor::dpl(unsigned int dpl) +{ + m_dpl = dpl; +} + +void* kernel::InterruptDescriptor::operator=(void* rhs) +{ + uint32_t offset = (uint32_t) rhs; + m_offset1 = (uint16_t) offset; + m_offset2 = (offset >> 16); +} diff --git a/src/interrupts/x86/interruptdescriptor.hpp b/src/interrupts/x86/interruptdescriptor.hpp new file mode 100644 index 0000000..c4365fe --- /dev/null +++ b/src/interrupts/x86/interruptdescriptor.hpp @@ -0,0 +1,55 @@ +#ifndef INTERRUPTDESCRIPTOR_H +#define INTERRUPTDESCRIPTOR_H + +#include + +namespace kernel +{ + +class InterruptDescriptor +{ +public: + + enum Type + { + TASK32 = 5, + TRAP32 = 15, + INT32 = 14, + TRAP16 = 7, + INT16 = 6 + }; + + InterruptDescriptor(); + + InterruptDescriptor(void* handler, Type type, unsigned int dpl); + + bool present(); + + void present(bool present); + + Type type(); + + void type(Type type); + + unsigned int dpl(); + + void dpl(unsigned int dpl); + + void* operator=(void* rhs); + +private: + + uint16_t m_offset1; + uint16_t m_selector; + uint16_t m_zero : 8; + uint16_t m_type : 4; + uint16_t m_storage : 1; + uint16_t m_dpl : 2; + uint16_t m_present : 1; + uint16_t m_offset2; + +}; + +} + +#endif diff --git a/src/interrupts/x86/interrupts.cpp b/src/interrupts/x86/interrupts.cpp new file mode 100644 index 0000000..971e6a8 --- /dev/null +++ b/src/interrupts/x86/interrupts.cpp @@ -0,0 +1,19 @@ +#include "../interrupts.hpp" +#include "idt.hpp" + +kernel::Interrupts::Interrupts() +{ + // Load interrupt handlers + // Configure PIC + _lidt(); +} + +inline void kernel::Interrupts::enable() +{ + asm("sti"); +} + +inline void kernel::Interrupts::disable() +{ + asm("cli"); +} \ No newline at end of file diff --git a/src/interrupts/x86/inthandlers.cpp b/src/interrupts/x86/inthandlers.cpp new file mode 100644 index 0000000..59ce3ad --- /dev/null +++ b/src/interrupts/x86/inthandlers.cpp @@ -0,0 +1,32 @@ +#include "inthandlers.hpp" + +char* display = (char*) 0xC00B8000; + +__attribute__ ((interrupt)) +void divisionByZero(void* frame) +{ + *display = 'z'; + display += 2; +} + +__attribute__ ((interrupt)) +void gpFaultHandler(void* frame, unsigned int error) +{ + *display = 'a'; + asm("hlt"); +} + +__attribute__ ((interrupt)) +void pageFaultHandler(void* frame, unsigned int error) +{ + *display = '0'; + //asm("hlt"); +} + +__attribute__ ((interrupt)) +void doubleFaultHandler(void* frame, unsigned int error) +{ + *display = '#'; + //asm("hlt"); +} + diff --git a/src/interrupts/x86/inthandlers.hpp b/src/interrupts/x86/inthandlers.hpp new file mode 100644 index 0000000..10f085b --- /dev/null +++ b/src/interrupts/x86/inthandlers.hpp @@ -0,0 +1,16 @@ +#ifndef INTHANDLERS_H +#define INTHANDLERS_H + +__attribute__ ((interrupt)) +void divisionByZero(void* frame); + +__attribute__ ((interrupt)) +void gpFaultHandler(void* frame, unsigned int error); + +__attribute__ ((interrupt)) +void pageFaultHandler(void* frame, unsigned int error); + +__attribute__ ((interrupt)) +void doubleFaultHandler(void* frame, unsigned int error); + +#endif diff --git a/src/linker.ld b/src/linker.ld new file mode 100755 index 0000000..36695c7 --- /dev/null +++ b/src/linker.ld @@ -0,0 +1,36 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0xC0100000; + VIRTUAL_BASE = .; + PHYSICAL_BASE = 0x100000; + BASE_DIFF = VIRTUAL_BASE - PHYSICAL_BASE; + + .text BLOCK(4K) : ALIGN(4K) + { + *(.multiboot) + *(.text) + } + + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + + .data BLOCK(4K) : ALIGN(4K) + { + *(.data) + } + + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } + + LOAD_START = ADDR(.text) - (VIRTUAL_BASE - PHYSICAL_BASE); + LOAD_END = ADDR(.data) + SIZEOF(.data) - (VIRTUAL_BASE - PHYSICAL_BASE); + BSS_END = ADDR(.bss) + SIZEOF(.bss) - (VIRTUAL_BASE - PHYSICAL_BASE); + IMAGE_SIZE = ((BSS_END - LOAD_START) + (4096 - ((BSS_END - LOAD_START) % 4096))) / 4096; +} diff --git a/src/math.cpp b/src/math.cpp old mode 100644 new mode 100755 diff --git a/src/math.h b/src/math.h old mode 100644 new mode 100755 diff --git a/src/memoryallocator.hpp b/src/memoryallocator.hpp new file mode 100755 index 0000000..48ea87c --- /dev/null +++ b/src/memoryallocator.hpp @@ -0,0 +1,55 @@ +#ifndef __MEMORYALLOCATOR_H_ +#define __MEMORYALLOCATOR_H_ + +#include +#include "systypes.hpp" + +namespace kernel +{ + +/** + * Interface for a dymanic memory allocator. + */ +class MemoryAllocator +{ +public: + + /** + * Allocate a block of memory containing 'size' bytes. May round up + * depending on the implementation. + */ + virtual physaddr_t allocate(size_t size) = 0; + + /** + * Free the region of memory starting at 'location' and containing + * 'size' bytes. + */ + virtual void free(physaddr_t location, size_t size) = 0; + + /** + * @returns the total number of free blocks of memory. + */ + virtual size_t freeBlocks() const = 0; + + /** + * @returns the size in blocks of the largest possible allocation that + * will not fail due to lack of memory. + */ + virtual size_t maxAllocationSize() const = 0; + + /** + * @returns the size in bytes of a single block. + */ + virtual size_t getBlockSize() const = 0; + + /** + * @returns the total number of blocks managed by this memory + * allocator. + */ + virtual size_t getMemorySize() const = 0; + +}; + +} + +#endif diff --git a/src/memorymap.cpp b/src/memorymap.cpp new file mode 100644 index 0000000..2935778 --- /dev/null +++ b/src/memorymap.cpp @@ -0,0 +1,38 @@ +#include "memorymap.hpp" + +kernel::MemoryMap::MemoryMap(kernel::MemoryMap::Region* map, size_t entries) +{ + this->map = map; + this->entries = entries; +} + +kernel::MemoryMap::Region& kernel::MemoryMap::operator[](size_t index) +{ + return map[index]; +} + +size_t kernel::MemoryMap::size() +{ + return entries; +} + +physaddr_t kernel::MemoryMap::Region::getLocation() +{ + return location; +} + +size_t kernel::MemoryMap::Region::getSize() +{ + return size; +} + +kernel::MemoryMap::Type kernel::MemoryMap::Region::getType() +{ + return (Type) type; +} + +bool kernel::MemoryMap::Region::contains(physaddr_t location, size_t size) +{ + return (location >= this->location) && + (location + size <= this->location + this->size); +} diff --git a/src/memorymap.hpp b/src/memorymap.hpp new file mode 100644 index 0000000..853927a --- /dev/null +++ b/src/memorymap.hpp @@ -0,0 +1,61 @@ +#ifndef MEMORYMAP_H +#define MEMORYMAP_H + +#include +#include + +#include "systypes.hpp" + +namespace kernel +{ + +class MemoryMap +{ +public: + + enum Type + { + AVAILABLE = 1, + ACPI = 3, + DEFECTIVE = 5 + }; + + class Region + { + public: + + physaddr_t getLocation(); + + size_t getSize(); + + Type getType(); + + bool contains(physaddr_t location, size_t size); + + private: + + physaddr_t location; + + size_t size; + + uint32_t type; + + }; + + MemoryMap(Region* map, size_t entries); + + Region& operator[](size_t index); + + size_t size(); + +private: + + Region* map; + + size_t entries; + +}; + +} + +#endif diff --git a/src/multiboot2header.S b/src/multiboot2header.S old mode 100644 new mode 100755 index 8f6f476..44bc2f3 --- a/src/multiboot2header.S +++ b/src/multiboot2header.S @@ -28,7 +28,7 @@ .set tagEntryType, 3 .set tagEntrySize, 12 -.set tagEntryAddress, _start - (0xC0000000 - 0x100000) +.set tagEntryAddress, _start - (0xC0100000 - 0x100000) .set tagModuleAlignType, 6 .set tagModuleAlignSize, 8 diff --git a/src/pagetableentry.cpp b/src/pagetableentry.cpp old mode 100644 new mode 100755 index 97ceb31..f84c477 --- a/src/pagetableentry.cpp +++ b/src/pagetableentry.cpp @@ -5,9 +5,9 @@ * Author: nathan */ -#include "pagetableentry.h" +#include "pagetableentry.hpp" -namespace qkernel { +namespace kernel { static_assert(sizeof(PageTableEntry) == 4, "PTE structure is the wrong size!"); @@ -26,102 +26,108 @@ PageTableEntry::PageTableEntry() { this->physicalAddress = 0; } -uint32_t PageTableEntry::getAccessed() const { - return accessed; +bool PageTableEntry::getAccessed() const { + return accessed == 1; } -uint32_t PageTableEntry::getCacheDisable() const { - return cacheDisable; -} - -void PageTableEntry::setCacheDisable(uint32_t cacheDisable) +bool PageTableEntry::getCacheDisable() const { - this->cacheDisable = cacheDisable; + return cacheDisable == 1; } -uint32_t PageTableEntry::getDirty() const { - return dirty; -} - -uint32_t PageTableEntry::getGlobal() const { - return global; -} - -void PageTableEntry::setGlobal(uint32_t global) +void PageTableEntry::setCacheDisable(bool cacheDisable) { - this->global = global; + this->cacheDisable = cacheDisable ? 1 : 0; } -uint32_t PageTableEntry::getPat() const { - return pat; -} - -void PageTableEntry::setPat(uint32_t pat) +bool PageTableEntry::getDirty() const { - this->pat = pat; + return dirty == 1; } -uint32_t PageTableEntry::getPhysicalAddress() const { - uint32_t physicalAddress = this->physicalAddress; +bool PageTableEntry::getGlobal() const +{ + return global == 1; +} + +void PageTableEntry::setGlobal(bool global) +{ + this->global = global ? 1 : 0; +} + +bool PageTableEntry::getPat() const +{ + return pat == 1; +} + +void PageTableEntry::setPat(bool pat) +{ + this->pat = pat ? 1 : 0; +} + +physaddr_t PageTableEntry::getPhysicalAddress() const { + physaddr_t physicalAddress = this->physicalAddress; return physicalAddress << 12; } -uint32_t PageTableEntry::setPhysicalAddress(uint32_t physicalAddress) +physaddr_t PageTableEntry::setPhysicalAddress(physaddr_t physicalAddress) { - if(physicalAddress % 4096 == 0) - { - this->physicalAddress = physicalAddress >> 12; - return this->physicalAddress; - } - else - { - this->physicalAddress = !physicalAddress; - return this->physicalAddress; - } + this->physicalAddress = physicalAddress >> 12; + return this->physicalAddress << 12; } -uint32_t PageTableEntry::getPresent() const { - return present; -} - -void PageTableEntry::setPresent(uint32_t present) +bool PageTableEntry::getPresent() const { - this->present = present; + return present == 1; } -uint32_t PageTableEntry::getRw() const { - return rw; -} - -void PageTableEntry::setRw(uint32_t rw) +void PageTableEntry::setPresent(bool present) { - this->rw = rw; + this->present = present ? 1 : 0; } -uint32_t PageTableEntry::getUsermode() const { - return usermode; -} - -void PageTableEntry::setUsermode(uint32_t usermode) +bool PageTableEntry::getRw() const { - this->usermode = usermode; + return rw == 1; } -uint32_t PageTableEntry::getWriteThrough() const { - return writeThrough; -} - -uint32_t PageTableEntry::getShared() const { - return shared; -} - -void PageTableEntry::setShared(uint32_t shared) { - this->shared = shared; -} - -void PageTableEntry::setWriteThrough(uint32_t writeThrough) +void PageTableEntry::setRw(bool rw) { - this->writeThrough = writeThrough; + this->rw = rw ? 1 : 0; +} + +bool PageTableEntry::getUsermode() const +{ + return usermode == 1; +} + +void PageTableEntry::setUsermode(bool usermode) +{ + this->usermode = usermode ? 1 : 0; +} + +bool PageTableEntry::getWriteThrough() const { + return writeThrough == 1; +} + +bool PageTableEntry::getShared() const +{ + return shared == 1; +} + +void PageTableEntry::setShared(bool shared) +{ + this->shared = shared ? 1 : 0; +} + +void PageTableEntry::setWriteThrough(bool writeThrough) +{ + this->writeThrough = writeThrough ? 1 : 0; +} + +physaddr_t PageTableEntry::operator=(physaddr_t rhs) +{ + return setPhysicalAddress(rhs); } } /* namespace qkernel */ diff --git a/src/pagetableentry.h b/src/pagetableentry.h deleted file mode 100644 index 021b942..0000000 --- a/src/pagetableentry.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * PageTableEntry.h - * - * Created on: May 22, 2019 - * Author: nathan - */ - -#ifndef SRC_PAGETABLEENTRY_H_ -#define SRC_PAGETABLEENTRY_H_ - -#include - -namespace qkernel { - -class PageTableEntry { -public: - PageTableEntry(); - uint32_t getAccessed() const; - uint32_t getCacheDisable() const; - void setCacheDisable(uint32_t cacheDisable); - uint32_t getDirty() const; - uint32_t getGlobal() const; - void setGlobal(uint32_t global); - uint32_t getPat() const; - void setPat(uint32_t pat); - uint32_t getPhysicalAddress() const; - uint32_t setPhysicalAddress(uint32_t physicalAddress); - uint32_t getPresent() const; - void setPresent(uint32_t present); - uint32_t getRw() const; - void setRw(uint32_t rw); - uint32_t getShared() const; - void setShared(uint32_t shared); - uint32_t getUsermode() const; - void setUsermode(uint32_t usermode); - uint32_t getWriteThrough() const; - void setWriteThrough(uint32_t writeThrough); - -private: - uint32_t present : 1; - uint32_t rw : 1; - uint32_t usermode : 1; - uint32_t writeThrough : 1; - uint32_t cacheDisable : 1; - uint32_t accessed : 1; - uint32_t dirty : 1; - uint32_t pat : 1; - uint32_t global : 1; - uint32_t shared : 1; - uint32_t ignored : 2; - uint32_t physicalAddress : 20; -}; - -} /* namespace qkernel */ - -#endif /* SRC_PAGETABLEENTRY_H_ */ diff --git a/src/pagetableentry.hpp b/src/pagetableentry.hpp new file mode 100755 index 0000000..0200953 --- /dev/null +++ b/src/pagetableentry.hpp @@ -0,0 +1,58 @@ +/* + * PageTableEntry.h + * + * Created on: May 22, 2019 + * Author: nathan + */ + +#ifndef SRC_PAGETABLEENTRY_H_ +#define SRC_PAGETABLEENTRY_H_ + +#include +#include "systypes.hpp" + +namespace kernel { + +class PageTableEntry { +public: + PageTableEntry(); + bool getAccessed() const; + bool getCacheDisable() const; + void setCacheDisable(bool cacheDisable); + bool getDirty() const; + bool getGlobal() const; + void setGlobal(bool global); + bool getPat() const; + void setPat(bool pat); + physaddr_t getPhysicalAddress() const; + physaddr_t setPhysicalAddress(physaddr_t physicalAddress); + bool getPresent() const; + void setPresent(bool present); + bool getRw() const; + void setRw(bool rw); + bool getShared() const; + void setShared(bool shared); + bool getUsermode() const; + void setUsermode(bool usermode); + bool getWriteThrough() const; + void setWriteThrough(bool writeThrough); + physaddr_t operator=(physaddr_t rhs); + +private: + uint32_t present : 1; + uint32_t rw : 1; + uint32_t usermode : 1; + uint32_t writeThrough : 1; + uint32_t cacheDisable : 1; + uint32_t accessed : 1; + uint32_t dirty : 1; + uint32_t pat : 1; + uint32_t global : 1; + uint32_t shared : 1; + uint32_t ignored : 2; + uint32_t physicalAddress : 20; +}; + +} /* namespace qkernel */ + +#endif /* SRC_PAGETABLEENTRY_H_ */ diff --git a/src/physicalmemoryallocator.cpp b/src/physicalmemoryallocator.cpp deleted file mode 100644 index 911a2f4..0000000 --- a/src/physicalmemoryallocator.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * PhysicalMemoryAllocator.cpp - * - * Created on: May 23, 2019 - * Author: nathan - */ - -#include "physicalmemoryallocator.h" -#include "math.h" -#include "error.h" - -namespace qkernel { - -void* const PhysicalMemoryAllocator::nullPtr = (void*) -1; - -PhysicalMemoryAllocator::PhysicalMemoryAllocator() -{ - for(size_t i = 0; i <= treeHeight; i++) - { - memoryMaps[i] = Bitmap(!available); - } - memoryMaps[treeHeight][0] = available; -} - -PhysicalMemoryAllocator::~PhysicalMemoryAllocator() -{ - // TODO Auto-generated destructor stub -} - -void* PhysicalMemoryAllocator::allocate(uint32_t pages) -{ - uint32_t height = ilog2(pages, true); - if(height >= treeHeight) // We can't allocate the whole address space at once! - { - return (void*) nullPtr; - } - - uint32_t index = findFreeBlock(height); - if(index != nullIndex) - { - memoryMaps[height][index] = !available; - return nodeToAddress(height, index); - } - else - { - return nullPtr; - } -} - -void PhysicalMemoryAllocator::free(void* location, uint32_t pages) -{ - uint32_t height = ilog2(pages, true); - if(height >= treeHeight || reinterpret_cast(location) % (4096 * pages) != 0) // We can't free the whole address space at once! - { - return; - } - - uint32_t index = addressToNode(height, location); - memoryMaps[height][index] = available; - - if(memoryMaps[height][getBuddy(index)] == available) - { - merge(height, index); - } -} - -uint32_t PhysicalMemoryAllocator::totalFreePages() -{ - uint32_t count = 0; - for(size_t i = 0; i <= treeHeight; i++) - { - count += (1 << i) * memoryMaps[i].count(); - } - return count; -} - -uint32_t PhysicalMemoryAllocator::largestFreeBlock() -{ - for(size_t i = treeHeight; i >= 0; i--) - { - if(memoryMaps[i].any()) - { - return 1 << i; - } - } -} - -uint32_t PhysicalMemoryAllocator::findFreeBlock(uint32_t height) -{ - if(memoryMaps[height].none()) - { - if(height == treeHeight) - { - lastError = Error(ErrorType::outOfMemory, "Out of memory"); - return nullIndex; - } - else - { - uint32_t parentIndex = findFreeBlock(height + 1); - if(parentIndex == (uint32_t) -1) - { - lastError = Error(ErrorType::outOfMemory, "Out of memory"); - return nullIndex; - } - split(height + 1, parentIndex); - } - - } - for(size_t index = 0; index < nodesAtHeight(height); index++) - { - if(memoryMaps[height][index] == available) - { - return index; - } - } - lastError = Error(ErrorType::illegalState, "There were still no free blocks after splitting larger ones!"); - return nullIndex; -} - -uint32_t PhysicalMemoryAllocator::merge(uint32_t height, uint32_t index) -{ - if(height == treeHeight) - { - lastError = Error(ErrorType::outOfBounds, "Attempted to merge root node"); - return nullIndex; - } - - if(memoryMaps[height][index] == 0 && memoryMaps[height][getBuddy(index)] == 0) - { - memoryMaps[height][index] = !available; - memoryMaps[height][getBuddy(index)] = !available; - memoryMaps[height + 1][getParent(index)] = available; - if(height + 1 < 20) - { - if(memoryMaps[height + 1][getBuddy(getParent(index))] == available) - { - return merge(height + 1, getParent(index)); - } - } - return getParent(index); - } - else - { - lastError = Error(ErrorType::invalidArgument, "Attempted to merge a node that is in use"); - return nullIndex; - } -} - -uint32_t PhysicalMemoryAllocator::split(uint32_t height, uint32_t index) -{ - if(height == 0) - { - lastError = Error(ErrorType::outOfBounds, "Attempted to split leaf node"); - return nullIndex; - } - - if(memoryMaps[height][index] == available) - { - memoryMaps[height][index] = !available; - memoryMaps[height - 1][getChild(index)] = available; - memoryMaps[height - 1][getBuddy(getChild(index))] = available; - return getChild(index); - } - else - { - lastError = Error(ErrorType::invalidArgument, "Attempted to split node currently in use"); - return nullIndex; - } -} - -uint32_t PhysicalMemoryAllocator::getBuddy(uint32_t index) -{ - return index ^ 1; -} - -uint32_t PhysicalMemoryAllocator::getParent(uint32_t index) -{ - return (index - index % 2) / 2; -} - -uint32_t PhysicalMemoryAllocator::getChild(uint32_t index) -{ - return index * 2; -} - -void* PhysicalMemoryAllocator::nodeToAddress(uint32_t height, uint32_t index) -{ - return reinterpret_cast(index * 4096 * (1 << height)); -} - -uint32_t PhysicalMemoryAllocator::nodesAtHeight(uint32_t height) -{ - return treeLeaves / (1 << height); -} - -uint32_t PhysicalMemoryAllocator::addressToNode(uint32_t height, - void* address) -{ - return reinterpret_cast(address) / (4096 * (1 << height)); -} - -} /* namespace qkernel */ diff --git a/src/physicalmemoryallocator.h b/src/physicalmemoryallocator.h deleted file mode 100644 index 11b0dc0..0000000 --- a/src/physicalmemoryallocator.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * PhysicalMemoryAllocator.h - * - * Created on: May 23, 2019 - * Author: nathan - */ - -#ifndef PHYSICALMEMORYALLOCATOR_H_ -#define PHYSICALMEMORYALLOCATOR_H_ - -#include -#include -#include "bitmap.h" - -namespace qkernel { - -class PhysicalMemoryAllocator { -public: - - static void* const nullPtr; - - PhysicalMemoryAllocator(); - - ~PhysicalMemoryAllocator(); - - void* allocate(uint32_t pages); - - void free(void* location, uint32_t pages); - - uint32_t totalFreePages(); - - uint32_t largestFreeBlock(); - -private: - - static const uint32_t nullIndex = (uint32_t) -1; - - static const bool available = true; - - static const size_t treeHeight = 20; - - static const size_t treeLeaves = 1024 * 1024; - - Bitmap memoryMaps[treeHeight + 1]; - - /** - * Searches nodes of the given height for an available block. If none is - * present, recursively splits higher nodes until one is. - * - * @param height The height of the desired node. - * @returns the index of the located node - */ - uint32_t findFreeBlock(uint32_t height); - - /** - * Merges a pair of buddies that have both become available. Recurses if - * the buddy of the new block is available. - * - * @param height The height of the blocks to merge. - * @param index The index of one of the buddies to be merged. - */ - uint32_t merge(uint32_t height, uint32_t index); - - /** - * Splits a block into a pair of buddies, making the original unavailable. - * - * @param height The height of the block to split. - * @param index The index of the block to split. - * - * @returns the index of the first of the pair of new blocks. - */ - uint32_t split(uint32_t height, uint32_t index); - - uint32_t getBuddy(uint32_t index); - - uint32_t getParent(uint32_t index); - - uint32_t getChild(uint32_t index); - - uint32_t nodesAtHeight(uint32_t height); - - void* nodeToAddress(uint32_t height, uint32_t index); - - uint32_t addressToNode(uint32_t height, void* address); - -}; - -} /* namespace qkernel */ - -#endif /* PHYSICALMEMORYALLOCATOR_H_ */ diff --git a/src/pio.S b/src/pio.S new file mode 100644 index 0000000..7681ee0 --- /dev/null +++ b/src/pio.S @@ -0,0 +1,13 @@ +.global outb +outb: + mov 4(%esp), %dx + mov 8(%esp), %al + out %al, %dx + ret + +.global inb +inb: + mov 4(%esp), %dx + xor %eax, %eax + in %dx, %al + ret \ No newline at end of file diff --git a/src/pio.hpp b/src/pio.hpp new file mode 100644 index 0000000..68aed33 --- /dev/null +++ b/src/pio.hpp @@ -0,0 +1,8 @@ +#ifndef PIO_H +#define PIO_H + +extern "C" void outb(short port, char data); + +extern "C" char inb(short port); + +#endif \ No newline at end of file diff --git a/src/quarkkernel.cpp b/src/quarkkernel.cpp old mode 100644 new mode 100755 index 17aa0fd..d607169 --- a/src/quarkkernel.cpp +++ b/src/quarkkernel.cpp @@ -1,13 +1,42 @@ #include #include -#if __STDC_HOSTED__ == 1 || __i686__ != 1 -#error "ERROR: This program must be compiled for a freestanding environment, and currently only supports the i686 target." -#endif +#include "systypes.hpp" +#include "systeminfo.hpp" +#include "memorymap.hpp" +#include "buddyallocator.hpp" +#include "addressspace.hpp" +#include "pio.hpp" +#include "tty.h" -void main() +using namespace kernel; + +extern SystemInfo system_info; +extern MemoryMap::Region memory_map; + +extern "C" void __cxa_pure_virtual() { - int x = 2; - x -= 1; - return; + +} + +void main(char* cmdline) +{ + TTY tty((char*) 0xC00B8000); + tty << "--Quark Kernel--\n"; + tty << "Low memory: \t" << (int) system_info.getLowMemory() << " KiB\n"; + tty << "High memory:\t" << (int) system_info.getHighMemory() << " KiB\n"; + tty << "Type\t\tLocation\t\tSize\n"; + MemoryMap memmap(&memory_map, 16); + for(size_t i = 0; i < memmap.size() && memmap[i].getSize() > 0; i++) + { + tty << (int) memmap[i].getType() << "\t\t\t"; + tty << (void*) memmap[i].getLocation() << "\t\t"; + tty << (int) memmap[i].getSize() << "\n"; + } + BuddyAllocator alloc(memmap, (char*) 0xC0000000, system_info.getHighMemory() / 4 + 256, 6); + AddressSpace vmem(alloc); + vmem.mmap((void*) 0x80000000, 0x10000); + outb(0xa1, 0xff); + outb(0x21, 0xff); + tty << "Nothing left to do. Hanging.\n"; } diff --git a/src/systeminfo.cpp b/src/systeminfo.cpp new file mode 100644 index 0000000..0ed92e4 --- /dev/null +++ b/src/systeminfo.cpp @@ -0,0 +1,16 @@ +#include "systeminfo.hpp" + +size_t kernel::SystemInfo::getLowMemory() +{ + return lowMemory; +} + +size_t kernel::SystemInfo::getHighMemory() +{ + return highMemory; +} + +physaddr_t kernel::SystemInfo::getKernelBase() +{ + return kernelBase; +} diff --git a/src/systeminfo.hpp b/src/systeminfo.hpp new file mode 100644 index 0000000..33ef728 --- /dev/null +++ b/src/systeminfo.hpp @@ -0,0 +1,33 @@ +#ifndef SYSTEMINFO_H +#define SYSTEMINFO_H + +#include + +#include "systypes.hpp" + +namespace kernel +{ + +class SystemInfo +{ +public: + + size_t getLowMemory(); + + size_t getHighMemory(); + + physaddr_t getKernelBase(); + +private: + + size_t lowMemory; + + size_t highMemory; + + physaddr_t kernelBase; + +}; + +} + +#endif diff --git a/src/systypes.hpp b/src/systypes.hpp new file mode 100644 index 0000000..cf07e96 --- /dev/null +++ b/src/systypes.hpp @@ -0,0 +1,9 @@ +#ifndef SYSTYPES_H +#define SYSTYPES_H + +#include +#include + +typedef uint32_t physaddr_t; + +#endif diff --git a/src/tty.cpp b/src/tty.cpp new file mode 100644 index 0000000..dcb80d2 --- /dev/null +++ b/src/tty.cpp @@ -0,0 +1,125 @@ +#include +#include "tty.h" + +kernel::TTY::TTY(char* vga) +{ + this->vga = vga; + this->cursor = 0; + this->width = 0; + this->base = 10; +} + +kernel::TTY& kernel::TTY::operator<<(kernel::TTY::Format fmt) +{ + switch(fmt) + { + case Binary: + base = 2; + break; + case Decimal: + base = 10; + break; + case Hex: + base = 16; + break; + } +} + +kernel::TTY& kernel::TTY::operator<<(const char* str) +{ + return printString(str); +} + +kernel::TTY& kernel::TTY::operator<<(unsigned int n) +{ + return printNumber(n, base, width); +} + +kernel::TTY& kernel::TTY::operator<<(int n) +{ + return printNumber((unsigned int) n, base, width); +} + +kernel::TTY& kernel::TTY::operator<<(void* n) +{ + return printNumber((unsigned int) n, 16, 8); +} + +kernel::TTY& kernel::TTY::operator<<(char c) +{ + return putChar(c); +} + +void kernel::TTY::setWidth(size_t width) +{ + this->width = width; +} + +size_t kernel::TTY::getWidth() +{ + return width; +} + +void kernel::TTY::clear() +{ + for(int i = 0; i < 80*25; i++) + { + vga[i * 2] = ' '; + } + cursor = 0; +} + +kernel::TTY& kernel::TTY::printNumber(unsigned int n, size_t base, + size_t width) +{ + const char* digits = "0123456789ABCDEF"; + char str[33]; + size_t i = 1; + do + { + str[i] = digits[n % base]; + n /= base; + i++; + } while(n > 0); + while(i <= width) + { + str[i] = '0'; + i++; + } + str[0] = '\0'; + for(char* s = str + (i - 1); *s; s--) + { + putChar(*s); + } + return *this; +} + +kernel::TTY& kernel::TTY::printString(const char* str) +{ + while(*str) + { + putChar(*str); + str++; + } + return *this; +} + +kernel::TTY& kernel::TTY::putChar(char c) +{ + switch(c) + { + case '\n': + cursor = (cursor + 80) - (cursor % 80); + break; + case '\t': + cursor = (cursor + 4) - (cursor % 4); + break; + case '\r': + cursor -= cursor % 160; + break; + default: + vga[cursor * 2] = c; + cursor++; + } + return *this; +} diff --git a/src/tty.h b/src/tty.h new file mode 100644 index 0000000..47b5191 --- /dev/null +++ b/src/tty.h @@ -0,0 +1,60 @@ +#ifndef TTY_H_ +#define TTY_H_ + +#include + +namespace kernel +{ + +class TTY +{ +public: + + enum Format + { + Binary, + Decimal, + Hex + }; + + TTY(char* vga); + + TTY& operator<<(Format fmt); + + TTY& operator<<(const char* str); + + TTY& operator<<(unsigned int n); + + TTY& operator<<(int n); + + TTY& operator<<(void* n); + + TTY& operator<<(char c); + + void setWidth(size_t width); + + size_t getWidth(); + + void clear(); + +private: + + TTY& printNumber(unsigned int n, size_t base, size_t width); + + TTY& printString(const char* str); + + TTY& putChar(char c); + + char* vga; + + int cursor; + + size_t width; + + size_t base; + +}; + +} + +#endif