commit adf531607d48365e442edcd1b9f21aa780e50b50 Author: Nathan Date: Tue Nov 26 15:23:54 2019 -0600 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..50372c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bin/qkernel +bin/*.o +bin/*~ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d3c84d7 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +===Quark Kernel=== \ No newline at end of file diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..82cf391 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,16 @@ +objs = math.o cstring.o error.o pagetableentry.o physicalmemoryallocator.o multiboot2header.o entry.o quarkkernel.o +link_script = linker.ld +quark_bin = qkernel + +CXX = i686-elf-g++ +CC = i686-elf-gcc + +CPPFLAGS += -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti + +all: $(objs) + echo $(PATH) + i686-elf-g++ -o $(quark_bin) -T $(link_script) -ffreestanding -nostdlib -O2 $(objs) -lgcc + +clean: + rm *.o + rm -f $(quark_bin) diff --git a/src/bitmap.h b/src/bitmap.h new file mode 100644 index 0000000..7e11b7b --- /dev/null +++ b/src/bitmap.h @@ -0,0 +1,609 @@ +/* + * 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/cstring.cpp b/src/cstring.cpp new file mode 100644 index 0000000..c30febb --- /dev/null +++ b/src/cstring.cpp @@ -0,0 +1,85 @@ +/* + * cstring.cpp + * + * Created on: Jun 13, 2019 + * Author: nathan + */ + +#include +#include +#include "cstring.h" + +void* memcpy(void* destination, const void* source, size_t num) +{ + if(num > 0) + { + const uint8_t* src = (const uint8_t*) source; + uint8_t* dest = (uint8_t*) destination; + for(size_t i = 0; i < num; i++) + { + dest[i] = src[i]; + } + } + return destination; +} + +/* + * There are four distinct cases here: + * 1. destination and source blocks do not overlap + * 2. destination and source are the same + * 3. destination and source do overlap; destination starts before source + * 4. destination and source do overlap; destination starts after source + * + * Memcpy results in expected behavior in all cases except for case 4. In that + * case, copying must be done backwards to avoid reading from bytes that have + * already been overwritten. + */ +void* memmove(void* destination, const void* source, size_t num) +{ + if(num > 0) + { + if(((size_t) destination) < ((size_t) source) || ((size_t) destination) >= (((size_t) source)) + num) + { + return memcpy(destination, source, num); + } + else if(destination != source) + { + size_t i = num - 1; + const uint8_t* src = (const uint8_t*) source; + uint8_t* dest = (uint8_t*) destination; + do + { + dest[i] = src[i]; + i--; + } while(i != 0); + } + } + return destination; +} + +int memcmp(const void* ptr1, const void* ptr2, size_t num) +{ + const uint8_t* a = (const uint8_t*) ptr1; + const uint8_t* b = (const uint8_t*) ptr2; + for(size_t i = 0; i < num; i++) + { + if(a[i] < b[i]) + return -1; + else if(a[i] > b[i]) + return 1; + } + return 0; +} + +void* memset (void* ptr, int value, size_t num) +{ + uint8_t* dest = (uint8_t*) ptr; + uint8_t v = (uint8_t) value; + for(size_t i = 0; i < num; i++) + { + dest[i] = v; + } + return ptr; +} + + diff --git a/src/cstring.h b/src/cstring.h new file mode 100644 index 0000000..3ea1763 --- /dev/null +++ b/src/cstring.h @@ -0,0 +1,26 @@ +/* + * cstring.h + * + * Created on: Jun 13, 2019 + * Author: nathan + */ + +#ifndef SRC_CSTRING_H_ +#define SRC_CSTRING_H_ + +#include + +extern "C" +{ + +void* memcpy(void* destination, const void* source, size_t num); + +void* memmove(void* destination, const void* source, size_t num); + +int memcmp(const void* ptr1, const void* ptr2, size_t num); + +void* memset (void* ptr, int value, size_t num); + +} + +#endif /* SRC_CSTRING_H_ */ diff --git a/src/entry.S b/src/entry.S new file mode 100644 index 0000000..b0dd842 --- /dev/null +++ b/src/entry.S @@ -0,0 +1,71 @@ +.section .multiboot +.include "multiboot2header.S" + +.section .bss + +.align 16 +stackBottom: +.skip 16384 +stackTop: + +.align 4096 +_tempPgDir: +.skip 4096 +_tempIdentityMap: +.skip 4096 +_tempPgTable: +.skip 4096 + +.section .text +.global _start +.type _start, @function +_start: + cmp $0x36d76289, %eax + jne _err + + movb $64, 0xB8000 + + mov $0, %ecx +1: mov %ecx, %eax + mov $4096, %edx + mul %edx + add $PHYSICAL_BASE, %eax + or $3, %eax + mov $_tempPgTable, %edi + mov %eax, (%edi, %ecx, 4) + mov $_tempIdentityMap, %edi + mov %eax, 1024(%edi, %ecx, 4) + inc %ecx + cmp $IMAGE_SIZE, %ecx + jne 1b + + mov $_tempIdentityMap, %eax + or $3, %eax + mov %eax, (_tempPgDir) + + mov $_tempPgTable, %eax + or $3, %eax + mov %eax, (_tempPgDir + 3072) + + mov $_tempPgDir, %eax + mov %eax, %cr3 + + mov %cr0, %eax + or $0x80010000, %eax + mov %eax, %cr0 + lea 2f, %eax + jmp *%eax +2: movl $0, (_tempIdentityMap) + mov %cr3, %eax + mov %eax, %cr3 + + mov $stackTop, %esp + + call main + +_err: + cli +3: hlt + jmp 3b + +.size _start, . - _start diff --git a/src/error.cpp b/src/error.cpp new file mode 100644 index 0000000..b22ff75 --- /dev/null +++ b/src/error.cpp @@ -0,0 +1,33 @@ +/* + * 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 new file mode 100644 index 0000000..eeddde1 --- /dev/null +++ b/src/error.h @@ -0,0 +1,40 @@ +/* + * 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 new file mode 100644 index 0000000..e4307f6 --- /dev/null +++ b/src/errortype.h @@ -0,0 +1,22 @@ +/* + * 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/math.cpp b/src/math.cpp new file mode 100644 index 0000000..caedfc6 --- /dev/null +++ b/src/math.cpp @@ -0,0 +1,27 @@ +/* + * math.cpp + * + * Created on: May 23, 2019 + * Author: nathan + */ + +#include "math.h" + +uint32_t ilog2(uint32_t n, bool roundUp) +{ + uint32_t m = n; + uint32_t count = 0; + bool isPowerOfTwo = true; + while(m) + { + if((m & 1) == 1 && m > 1) + { + isPowerOfTwo = false; + } + count++; + m >>= 1; + } + return count - (isPowerOfTwo ? 1 : (roundUp ? 0 : 1)); +} + + diff --git a/src/math.h b/src/math.h new file mode 100644 index 0000000..150df64 --- /dev/null +++ b/src/math.h @@ -0,0 +1,22 @@ +/* + * math.h + * + * Created on: May 23, 2019 + * Author: nathan + */ + +#ifndef SRC_MATH_H_ +#define SRC_MATH_H_ + +#include + +/** + * Computes the logarithm in base 2 of a given integer, returning an integer as + * the result. For n = -1, returns unsigned -1. + * + * @returns floor(log2(n)), where n > 0. Else unsigned -1. + */ +uint32_t ilog2(uint32_t n, bool roundUp = false); + + +#endif /* SRC_MATH_H_ */ diff --git a/src/multiboot2header.S b/src/multiboot2header.S new file mode 100644 index 0000000..8f6f476 --- /dev/null +++ b/src/multiboot2header.S @@ -0,0 +1,94 @@ +/* + * Define constants for the multiboot header. See Multuboot 2 Specifications for details. + */ +.set align, 1<<0 +.set meminfo, 1<<1 +.set magic, 0xE85250D6 +.set arch, 0 +.set headerLength, _multibootHeaderEnd - _multibootHeaderStart +.set checksum, -(magic + arch + headerLength) + +.set tagNotOptional, 0 + +.set tagInfoRequestType, 1 +.set tagInfoRequestSize, _multibootInfoTagEnd - _multibootInfoTagStart +.set requestBootCommand, 1 +.set requestBootLoaderName, 2 +.set requestBootModules, 3 +.set requestMemoryInfo, 4 +.set requestBootDevice, 5 +.set requestMemoryMap, 6 + +.set tagAddressType, 2 +.set tagAddressSize, 24 +.set tagAddressHeaderLocation, LOAD_START +.set tagAddressLoadStart, LOAD_START +.set tagAddressLoadEnd, LOAD_END +.set tagAddressBSSEnd, BSS_END + +.set tagEntryType, 3 +.set tagEntrySize, 12 +.set tagEntryAddress, _start - (0xC0000000 - 0x100000) + +.set tagModuleAlignType, 6 +.set tagModuleAlignSize, 8 + +/* + * Each multiboot tag must be 8-byte aligned, or GRUB will not be able to read the header. + */ +.align 8 +_multibootHeaderStart: + +.long magic +.long arch +.long headerLength +.long checksum + +.align 8 + +_multibootInfoTagStart: +.short tagInfoRequestType +.short tagNotOptional +.long tagInfoRequestSize +.long requestBootCommand +.long requestBootLoaderName +.long requestBootModules +.long requestMemoryInfo +.long requestBootDevice +.long requestMemoryMap +_multibootInfoTagEnd: + +.align 8 + +.short tagAddressType +.short tagNotOptional +.long tagAddressSize +.long tagAddressHeaderLocation +.long tagAddressLoadStart +.long tagAddressLoadEnd +.long tagAddressBSSEnd + +.align 8 + +.short tagEntryType +.short tagNotOptional +.long tagEntrySize +.long tagEntryAddress + +.align 8 + +.short tagModuleAlignType +.short tagNotOptional +.long tagModuleAlignSize + +.align 8 + +/* + * Terminate list of multiboot header tags. + * Ending tag has type = 0, flags = 0, size = 8 + */ +.long 0 +.long 8 + +_multibootHeaderEnd: + diff --git a/src/pagetableentry.cpp b/src/pagetableentry.cpp new file mode 100644 index 0000000..97ceb31 --- /dev/null +++ b/src/pagetableentry.cpp @@ -0,0 +1,127 @@ +/* + * PageTableEntry.cpp + * + * Created on: May 22, 2019 + * Author: nathan + */ + +#include "pagetableentry.h" + +namespace qkernel { + +static_assert(sizeof(PageTableEntry) == 4, "PTE structure is the wrong size!"); + +PageTableEntry::PageTableEntry() { + this->present = 0; + this->rw = 0; + this->usermode = 0; + this->writeThrough = 0; + this->cacheDisable = 0; + this->accessed = 0; + this->dirty = 0; + this->pat = 0; + this->global = 0; + this->shared = 0; + this->ignored = 0; + this->physicalAddress = 0; +} + +uint32_t PageTableEntry::getAccessed() const { + return accessed; +} + +uint32_t PageTableEntry::getCacheDisable() const { + return cacheDisable; +} + +void PageTableEntry::setCacheDisable(uint32_t cacheDisable) +{ + this->cacheDisable = cacheDisable; +} + +uint32_t PageTableEntry::getDirty() const { + return dirty; +} + +uint32_t PageTableEntry::getGlobal() const { + return global; +} + +void PageTableEntry::setGlobal(uint32_t global) +{ + this->global = global; +} + +uint32_t PageTableEntry::getPat() const { + return pat; +} + +void PageTableEntry::setPat(uint32_t pat) +{ + this->pat = pat; +} + +uint32_t PageTableEntry::getPhysicalAddress() const { + uint32_t physicalAddress = this->physicalAddress; + return physicalAddress << 12; +} + +uint32_t PageTableEntry::setPhysicalAddress(uint32_t physicalAddress) +{ + if(physicalAddress % 4096 == 0) + { + this->physicalAddress = physicalAddress >> 12; + return this->physicalAddress; + } + else + { + this->physicalAddress = !physicalAddress; + return this->physicalAddress; + } +} + +uint32_t PageTableEntry::getPresent() const { + return present; +} + +void PageTableEntry::setPresent(uint32_t present) +{ + this->present = present; +} + +uint32_t PageTableEntry::getRw() const { + return rw; +} + +void PageTableEntry::setRw(uint32_t rw) +{ + this->rw = rw; +} + +uint32_t PageTableEntry::getUsermode() const { + return usermode; +} + +void PageTableEntry::setUsermode(uint32_t usermode) +{ + this->usermode = usermode; +} + +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) +{ + this->writeThrough = writeThrough; +} + +} /* namespace qkernel */ diff --git a/src/pagetableentry.h b/src/pagetableentry.h new file mode 100644 index 0000000..021b942 --- /dev/null +++ b/src/pagetableentry.h @@ -0,0 +1,56 @@ +/* + * 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/physicalmemoryallocator.cpp b/src/physicalmemoryallocator.cpp new file mode 100644 index 0000000..911a2f4 --- /dev/null +++ b/src/physicalmemoryallocator.cpp @@ -0,0 +1,202 @@ +/* + * 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 new file mode 100644 index 0000000..11b0dc0 --- /dev/null +++ b/src/physicalmemoryallocator.h @@ -0,0 +1,90 @@ +/* + * 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/quarkkernel.cpp b/src/quarkkernel.cpp new file mode 100644 index 0000000..17aa0fd --- /dev/null +++ b/src/quarkkernel.cpp @@ -0,0 +1,13 @@ +#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 + +void main() +{ + int x = 2; + x -= 1; + return; +}