Initial commit

This commit is contained in:
2019-11-26 15:23:54 -06:00
commit adf531607d
18 changed files with 1537 additions and 0 deletions

16
src/Makefile Normal file
View File

@@ -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)

609
src/bitmap.h Normal file
View File

@@ -0,0 +1,609 @@
/*
* Bitmap.h
*
* Created on: Jun 1, 2019
* Author: nathan
*/
#ifndef SRC_BITMAP_H_
#define SRC_BITMAP_H_
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
namespace qkernel {
/**
* Represents a fixed array of N bits. Somewhat analogous to std::bitset. Can
* be manipulated using standard arithmetic operators (&, |, ^, ~).
*/
template <size_t N>
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<N>& 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<N>& set();
/**
* Clears all bits in this bitmap.
*
* @returns a reference to this bitmap
*/
Bitmap<N>& 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<N>& 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<N>& 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<N> operator&(const Bitmap<N>& other) const;
/**
* Sets the value of this bitmap to the bitwise AND of this bitmap and
* 'other.'
*
* @returns a reference to this bitmap
*/
Bitmap<N>& operator&=(const Bitmap<N>& other);
/**
* @returns a bitmap containing the bitwise OR of this bitmap and 'other.'
*/
Bitmap<N> operator|(const Bitmap<N>& other) const;
/**
* Sets the value of this bitmap to the bitwise OR of this bitmap and
* 'other.'
*
* @returns a reference to this bitmap
*/
Bitmap<N>& operator|=(const Bitmap<N>& other);
/**
* @returns a bitmap containing the bitwise XOR of this bitmap and 'other.'
*/
Bitmap<N> operator^(const Bitmap<N>& other) const;
/**
* Sets the value of this bitmap to the bitwise OR of this bitmap and
* 'other.'
*
* @returns a reference to this bitmap
*/
Bitmap<N>& operator^=(const Bitmap<N>& other);
/**
* Shifts this bitmap 'n' bits left.
*
* @returns a new Bitmap containing the result
*/
Bitmap<N> operator<<(const size_t n) const;
/**
* Shifts this bitmap 'n' bits left.
*
* @returns a reference to this bitmap
*/
Bitmap<N>& operator<<=(const size_t n);
/**
* Shifts this bitmap 'n' bits right.
*
* @returns a new Bitmap containing the result
*/
Bitmap<N> operator>>(const size_t n) const;
/**
* Shifts the bitmap 'n' bits right.
*
* @returns a reference to this bitmap
*/
Bitmap<N>& operator>>=(const size_t n);
/**
* Computes the bitwise NOT of this bitmap
*
* @returns a new bitmap containing the result
*/
Bitmap<N> operator~() const;
private:
uint8_t data[(N / 8) + 1];
};
} /* namespace qkernel */
template<size_t N>
inline qkernel::Bitmap<N>::Reference::Reference(uint8_t& data, size_t position)
: data(data)
{
this->position = position;
}
template<size_t N>
inline typename qkernel::Bitmap<N>::Reference& qkernel::Bitmap<N>::Reference::operator =(const bool b) {
if(b)
{
data |= 1 << position;
}
else
{
data &= ~(1 << position);
}
return *this;
}
template<size_t N>
inline typename qkernel::Bitmap<N>::Reference& qkernel::Bitmap<N>::Reference::operator =(const Reference& r) {
if((bool) r)
{
data |= 1 << position;
}
else
{
data &= ~(1 << position);
}
}
template<size_t N>
inline bool qkernel::Bitmap<N>::Reference::operator ~() const {
return !((bool) (*this));
}
template<size_t N>
inline qkernel::Bitmap<N>::Reference::operator bool() const {
uint8_t value = data & (1 << position);
if((data & (1 << position)) != 0)
{
return true;
}
else
{
return false;
}
}
template<size_t N>
inline qkernel::Bitmap<N>::Bitmap() {
}
template<size_t N>
inline qkernel::Bitmap<N>::Bitmap(const Bitmap<N>& bitmap) {
for(size_t i = 0; i < N; i++)
{
(*this)[i] = bitmap[i];
}
}
template<size_t N>
inline qkernel::Bitmap<N>::Bitmap(const bool value) {
for(size_t i = 0; i < N; i++)
{
(*this)[i] = value;
}
}
template<size_t N>
inline qkernel::Bitmap<N>::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<size_t N>
inline qkernel::Bitmap<N>::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<size_t N>
inline qkernel::Bitmap<N>::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<size_t N>
inline size_t qkernel::Bitmap<N>::size() {
return N;
}
template<size_t N>
inline size_t qkernel::Bitmap<N>::count() {
size_t count = 0;
for(size_t i = 0; i < N; i++)
{
if((*this)[i] == true)
{
count++;
}
}
return count;
}
template<size_t N>
inline bool qkernel::Bitmap<N>::all() {
for(size_t i = 0; i < N; i++)
{
if((*this)[i] == false)
{
return false;
}
}
return true;
}
template<size_t N>
inline bool qkernel::Bitmap<N>::any() {
for(size_t i = 0; i < N; i++)
{
if((*this)[i] == true)
{
return true;
}
}
return false;
}
template<size_t N>
inline bool qkernel::Bitmap<N>::none() {
for(size_t i = 0; i < N; i++)
{
if((*this)[i] == true)
{
return false;
}
}
return true;
}
template<size_t N>
inline qkernel::Bitmap<N>& qkernel::Bitmap<N>::set() {
for(size_t i = 0; i < N; i++)
{
(*this)[i] = true;
}
return *this;
}
template<size_t N>
inline qkernel::Bitmap<N>& qkernel::Bitmap<N>::clear() {
for(size_t i = 0; i < N; i++)
{
(*this)[i] = false;
}
return *this;
}
template<size_t N>
inline bool qkernel::Bitmap<N>::operator ==(const Bitmap<N>& other) const {
for(size_t i = 0; i < N; i++)
{
if((*this)[i] != other[i])
{
return false;
}
}
return true;
}
template<size_t N>
inline bool qkernel::Bitmap<N>::operator !=(const Bitmap<N>& other) const {
return !((*this) == other);
}
template<size_t N>
inline typename qkernel::Bitmap<N>::Reference qkernel::Bitmap<N>::operator [](const size_t index) {
return Reference(data[index / 8], index % 8);
}
template<size_t N>
inline bool qkernel::Bitmap<N>::operator [](const size_t index) const {
return (data[index/8] & (1 << (index % 8))) == 0 ? false : true;
}
template<size_t N>
inline qkernel::Bitmap<N> qkernel::Bitmap<N>::operator &(const Bitmap<N>& other) const {
Bitmap<N> result;
for(size_t i = 0; i < N; i++)
{
result[i] = (*this)[i] && other[i];
}
return result;
}
template<size_t N>
inline qkernel::Bitmap<N>& qkernel::Bitmap<N>::operator &=(const Bitmap<N>& other) {
for(size_t i = 0; i < N; i++)
{
(*this)[i] = (*this)[i] && other[i];
}
return *this;
}
template<size_t N>
inline qkernel::Bitmap<N> qkernel::Bitmap<N>::operator |(const Bitmap<N>& other) const {
Bitmap<N> result;
for(size_t i = 0; i < N; i++)
{
result[i] = (*this)[i] || other[i];
}
return result;
}
template<size_t N>
inline qkernel::Bitmap<N>& qkernel::Bitmap<N>::operator |=(const Bitmap<N>& other) {
for(size_t i = 0; i < N; i++)
{
(*this)[i] = (*this)[i] || other[i];
}
return *this;
}
template<size_t N>
inline qkernel::Bitmap<N> qkernel::Bitmap<N>::operator ^(const Bitmap<N>& other) const {
Bitmap<N> result;
for(size_t i = 0; i < N; i++)
{
result[i] = (*this)[i] ^ other[i];
}
return result;
}
template<size_t N>
inline qkernel::Bitmap<N>& qkernel::Bitmap<N>::operator ^=(const Bitmap<N>& other) {
for(size_t i = 0; i < N; i++)
{
(*this)[i] = (*this)[i] ^ other[i];
}
return *this;
}
template<size_t N>
inline qkernel::Bitmap<N> qkernel::Bitmap<N>::operator <<(const size_t n) const {
Bitmap<N> result;
for(size_t i = 0; i < N; i++)
{
if(i < n)
{
result[i] = false;
}
else
{
result[i] = (*this)[i-n];
}
}
return result;
}
template<size_t N>
inline qkernel::Bitmap<N>& qkernel::Bitmap<N>::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<size_t N>
inline qkernel::Bitmap<N> qkernel::Bitmap<N>::operator >>(const size_t n) const {
Bitmap<N> 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<size_t N>
inline qkernel::Bitmap<N>& qkernel::Bitmap<N>::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<size_t N>
inline qkernel::Bitmap<N> qkernel::Bitmap<N>::operator ~() const {
Bitmap<N> result;
for(size_t i = 0; i < N; i++)
{
result[i] = !(*this)[i];
}
return result;
}
#endif /* SRC_BITMAP_H_ */

85
src/cstring.cpp Normal file
View File

@@ -0,0 +1,85 @@
/*
* cstring.cpp
*
* Created on: Jun 13, 2019
* Author: nathan
*/
#include <stdint.h>
#include <stddef.h>
#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;
}

26
src/cstring.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* cstring.h
*
* Created on: Jun 13, 2019
* Author: nathan
*/
#ifndef SRC_CSTRING_H_
#define SRC_CSTRING_H_
#include <stddef.h>
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_ */

71
src/entry.S Normal file
View File

@@ -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

33
src/error.cpp Normal file
View File

@@ -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 */

40
src/error.h Normal file
View File

@@ -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_ */

22
src/errortype.h Normal file
View File

@@ -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_ */

27
src/math.cpp Normal file
View File

@@ -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));
}

22
src/math.h Normal file
View File

@@ -0,0 +1,22 @@
/*
* math.h
*
* Created on: May 23, 2019
* Author: nathan
*/
#ifndef SRC_MATH_H_
#define SRC_MATH_H_
#include <stdint.h>
/**
* 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_ */

94
src/multiboot2header.S Normal file
View File

@@ -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:

127
src/pagetableentry.cpp Normal file
View File

@@ -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 */

56
src/pagetableentry.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* PageTableEntry.h
*
* Created on: May 22, 2019
* Author: nathan
*/
#ifndef SRC_PAGETABLEENTRY_H_
#define SRC_PAGETABLEENTRY_H_
#include <stdint.h>
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_ */

View File

@@ -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<treeLeaves>(!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<uint32_t>(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<void*>(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<uint32_t>(address) / (4096 * (1 << height));
}
} /* namespace qkernel */

View File

@@ -0,0 +1,90 @@
/*
* PhysicalMemoryAllocator.h
*
* Created on: May 23, 2019
* Author: nathan
*/
#ifndef PHYSICALMEMORYALLOCATOR_H_
#define PHYSICALMEMORYALLOCATOR_H_
#include <stdint.h>
#include <stddef.h>
#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<treeLeaves> 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_ */

13
src/quarkkernel.cpp Normal file
View File

@@ -0,0 +1,13 @@
#include <stddef.h>
#include <stdint.h>
#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;
}