Initial commit
This commit is contained in:
16
src/Makefile
Normal file
16
src/Makefile
Normal 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
609
src/bitmap.h
Normal 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
85
src/cstring.cpp
Normal 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
26
src/cstring.h
Normal 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
71
src/entry.S
Normal 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
33
src/error.cpp
Normal 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
40
src/error.h
Normal 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
22
src/errortype.h
Normal 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
27
src/math.cpp
Normal 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
22
src/math.h
Normal 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
94
src/multiboot2header.S
Normal 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
127
src/pagetableentry.cpp
Normal 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
56
src/pagetableentry.h
Normal 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_ */
|
||||
202
src/physicalmemoryallocator.cpp
Normal file
202
src/physicalmemoryallocator.cpp
Normal 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 */
|
||||
90
src/physicalmemoryallocator.h
Normal file
90
src/physicalmemoryallocator.h
Normal 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
13
src/quarkkernel.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user