10
.gitignore
vendored
Normal file → Executable file
10
.gitignore
vendored
Normal file → Executable file
@@ -1,3 +1,7 @@
|
|||||||
bin/qkernel
|
quark.iso
|
||||||
bin/*.o
|
src/quark-kernel
|
||||||
bin/*~
|
src/interrupts/libinterrupts.a
|
||||||
|
*.o
|
||||||
|
*~
|
||||||
|
rootfs/
|
||||||
|
test/
|
||||||
14
Makefile
Normal file
14
Makefile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
.PHONY: all
|
||||||
|
all: quark.iso
|
||||||
|
|
||||||
|
quark.iso: src/quark-kernel
|
||||||
|
cp src/quark-kernel rootfs/apps
|
||||||
|
grub-mkrescue -o $@ rootfs
|
||||||
|
|
||||||
|
src/quark-kernel:
|
||||||
|
make -C src
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
make -C src clean
|
||||||
|
rm -f quark.iso
|
||||||
20
src/Makefile
20
src/Makefile
@@ -1,16 +1,18 @@
|
|||||||
objs = math.o cstring.o error.o pagetableentry.o physicalmemoryallocator.o multiboot2header.o entry.o quarkkernel.o
|
objs = addressspace.o tty.o buddyallocator.o math.o cstring.o pagetableentry.o multiboot2header.o systeminfo.o memorymap.o pio.o entry.o quarkkernel.o
|
||||||
link_script = linker.ld
|
|
||||||
quark_bin = qkernel
|
|
||||||
|
|
||||||
CXX = i686-elf-g++
|
CXX = i686-elf-g++
|
||||||
CC = i686-elf-gcc
|
CC = i686-elf-gcc
|
||||||
|
|
||||||
CPPFLAGS += -ffreestanding -O2 -Wall -Wextra -fno-exceptions -fno-rtti
|
CXXFLAGS = -ffreestanding -mgeneral-regs-only -O0 -Wall -fno-exceptions -fno-rtti -ggdb
|
||||||
|
LDFLAGS = -T linker.ld -lgcc -nostdlib
|
||||||
|
|
||||||
all: $(objs)
|
quark-kernel: $(objs) linker.ld interrupts/libinterrupts.a
|
||||||
echo $(PATH)
|
$(CXX) -o $@ $(LDFLAGS) interrupts/libinterrupts.a $(objs)
|
||||||
i686-elf-g++ -o $(quark_bin) -T $(link_script) -ffreestanding -nostdlib -O2 $(objs) -lgcc
|
|
||||||
|
|
||||||
|
interrupts/libinterrupts.a:
|
||||||
|
make -C interrupts CXX="$(CXX)" CC="$(CC)" CXXFLAGS="$(CXXFLAGS)"
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm *.o
|
make -C interrupts clean
|
||||||
rm -f $(quark_bin)
|
rm -f $(objs) quark-kernel
|
||||||
51
src/addressspace.cpp
Normal file
51
src/addressspace.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include "addressspace.hpp"
|
||||||
|
|
||||||
|
kernel::AddressSpace::AddressSpace(MemoryAllocator& malloc)
|
||||||
|
: malloc(malloc)
|
||||||
|
{
|
||||||
|
this->pageTables = (PageTableEntry*) 0xFFC00000;
|
||||||
|
this->pageDirectory = (PageTableEntry*) 0xFFFFF000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* kernel::AddressSpace::mmap(void* start, size_t length)
|
||||||
|
{
|
||||||
|
size_t tableIndex = (size_t) start / 4096;
|
||||||
|
for(int i = (int) length; i > 0; i -= 4096)
|
||||||
|
{
|
||||||
|
size_t directoryIndex = tableIndex / 1024;
|
||||||
|
if(!pageDirectory[directoryIndex].getPresent())
|
||||||
|
{
|
||||||
|
physaddr_t newPT = malloc.allocate(4096);
|
||||||
|
pageDirectory[directoryIndex] = newPT;
|
||||||
|
pageDirectory[directoryIndex].setPresent(true);
|
||||||
|
pageDirectory[directoryIndex].setUsermode(false);
|
||||||
|
pageDirectory[directoryIndex].setRw(true);
|
||||||
|
}
|
||||||
|
if(!pageTables[tableIndex].getPresent())
|
||||||
|
{
|
||||||
|
physaddr_t page = malloc.allocate(4096);
|
||||||
|
pageTables[tableIndex] = page;
|
||||||
|
pageTables[tableIndex].setUsermode(false);
|
||||||
|
pageTables[tableIndex].setRw(true);
|
||||||
|
pageTables[tableIndex].setPresent(true);
|
||||||
|
}
|
||||||
|
tableIndex++;
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel::AddressSpace::munmap(void* start, size_t length)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
physaddr_t kernel::AddressSpace::getPhysicalAddress(void* virtualAddress)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
size_t index = (size_t) virtualAddress / 4096;
|
||||||
|
PageTableEntry pte = pageTables[index];
|
||||||
|
if(pte.getPresent())
|
||||||
|
return pte.getPhysicalAddress();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
42
src/addressspace.hpp
Executable file
42
src/addressspace.hpp
Executable file
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef SRC_ADDRESSSPACE_H_
|
||||||
|
#define SRC_ADDRESSSPACE_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "memoryallocator.hpp"
|
||||||
|
#include "pagetableentry.hpp"
|
||||||
|
#include "systypes.hpp"
|
||||||
|
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
class AddressSpace {
|
||||||
|
public:
|
||||||
|
|
||||||
|
AddressSpace(MemoryAllocator& malloc);
|
||||||
|
|
||||||
|
void* mmap(void* start, size_t length);
|
||||||
|
|
||||||
|
void munmap(void* start, size_t length);
|
||||||
|
|
||||||
|
physaddr_t getPhysicalAddress(void* virtualAddress) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
MemoryAllocator& malloc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of 1024 page tables, each containing 1024 entries.
|
||||||
|
* The last table represents the page directory.
|
||||||
|
*/
|
||||||
|
PageTableEntry* pageTables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of 1024 PDEs, located at the end of the pageTables array
|
||||||
|
*/
|
||||||
|
PageTableEntry* pageDirectory;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace kernel */
|
||||||
|
|
||||||
|
#endif
|
||||||
609
src/bitmap.h
609
src/bitmap.h
@@ -1,609 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_ */
|
|
||||||
253
src/buddyallocator.cpp
Executable file
253
src/buddyallocator.cpp
Executable file
@@ -0,0 +1,253 @@
|
|||||||
|
#include "buddyallocator.hpp"
|
||||||
|
#include "math.h"
|
||||||
|
#include "systypes.hpp"
|
||||||
|
#include "memorymap.hpp"
|
||||||
|
|
||||||
|
#define roundUp(n, m) ((n % m == 0) ? n : (n + m - (n % m)))
|
||||||
|
|
||||||
|
kernel::BuddyAllocator::BuddyAllocator()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::BuddyAllocator::BuddyAllocator(kernel::MemoryMap& memmap,
|
||||||
|
char* bitmap, size_t blockCount,
|
||||||
|
size_t treeHeight)
|
||||||
|
{
|
||||||
|
this->bitmap = bitmap;
|
||||||
|
this->blockSize = 4096;
|
||||||
|
this->blockCount = blockCount;
|
||||||
|
this->treeHeight = treeHeight;
|
||||||
|
for(size_t i = 0; i <= treeHeight; i++)
|
||||||
|
{
|
||||||
|
for(size_t j = 0; j < (blockCount >> i); j++)
|
||||||
|
{
|
||||||
|
reserveNode(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
physaddr_t location = 0x100000;
|
||||||
|
for(size_t i = 0; i < memmap.size() && memmap[i].getSize() > 0; i++)
|
||||||
|
{
|
||||||
|
if(memmap[i].getType() != kernel::MemoryMap::AVAILABLE)
|
||||||
|
continue;
|
||||||
|
if(memmap[i].getLocation() > location)
|
||||||
|
location = roundUp(memmap[i].getLocation(), 4096);
|
||||||
|
while(memmap[i].contains(location, 4096))
|
||||||
|
{
|
||||||
|
freeNode(0, location / 4096);
|
||||||
|
if(isFree(0, getBuddy(location / 4096)))
|
||||||
|
merge(0, location / 4096);
|
||||||
|
location += 4096;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::BuddyAllocator::BuddyAllocator(char* bitmap, size_t blockSize,
|
||||||
|
size_t blockCount, size_t treeHeight)
|
||||||
|
{
|
||||||
|
this->bitmap = bitmap;
|
||||||
|
this->blockSize = blockSize;
|
||||||
|
this->blockCount = blockCount;
|
||||||
|
this->treeHeight = treeHeight;
|
||||||
|
for(size_t i = 0; i <= treeHeight; i++)
|
||||||
|
{
|
||||||
|
for(size_t j = 0; j < (blockCount >> i); j++)
|
||||||
|
{
|
||||||
|
if(i < treeHeight)
|
||||||
|
reserveNode(i, j);
|
||||||
|
else
|
||||||
|
freeNode(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
physaddr_t kernel::BuddyAllocator::allocate(size_t size)
|
||||||
|
{
|
||||||
|
size_t height = ilog2(roundUp(size, blockSize) / blockSize, true);
|
||||||
|
if(height > treeHeight) // Requested block size is greater than maximum
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t index = findFreeBlock(height);
|
||||||
|
if(index == INVALID) // Failed to find a big enough free block; out of memory
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reserveNode(height, index);
|
||||||
|
return nodeToAddress(height, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel::BuddyAllocator::free(physaddr_t location, size_t size)
|
||||||
|
{
|
||||||
|
size_t height = ilog2(roundUp(size, blockSize) / blockSize, true);
|
||||||
|
if(height <= treeHeight)
|
||||||
|
{
|
||||||
|
size_t index = addressToNode(height, location);
|
||||||
|
freeNode(height, index);
|
||||||
|
if(isFree(height, getBuddy(index)))
|
||||||
|
{
|
||||||
|
merge(height, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::freeBlocks() const
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
for(size_t j = 0; j < blockCount; j++)
|
||||||
|
{
|
||||||
|
if(isFree(0, j))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::maxAllocationSize() const
|
||||||
|
{
|
||||||
|
for(size_t i = treeHeight; i >= 0; i--)
|
||||||
|
{
|
||||||
|
for(size_t j = 0; j < (blockCount >> i); j++)
|
||||||
|
{
|
||||||
|
if(isFree(i, j))
|
||||||
|
{
|
||||||
|
return 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::getBlockSize() const
|
||||||
|
{
|
||||||
|
return blockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::getMemorySize() const
|
||||||
|
{
|
||||||
|
return blockCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::findFreeBlock(size_t height)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < (blockCount >> height); i++)
|
||||||
|
{
|
||||||
|
if(isFree(height, i))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(height < treeHeight)
|
||||||
|
{
|
||||||
|
size_t parentIndex = findFreeBlock(height + 1);
|
||||||
|
if(parentIndex != INVALID)
|
||||||
|
{
|
||||||
|
return split(height + 1, parentIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::split(size_t height, size_t index)
|
||||||
|
{
|
||||||
|
if(height > 0 && isFree(height, index))
|
||||||
|
{
|
||||||
|
reserveNode(height, index);
|
||||||
|
freeNode(height - 1, getChild(index));
|
||||||
|
freeNode(height - 1, getBuddy(getChild(index)));
|
||||||
|
return getChild(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::merge(size_t height, size_t index)
|
||||||
|
{
|
||||||
|
if(isFree(height, index) && isFree(height, getBuddy(index)) && height < treeHeight)
|
||||||
|
{
|
||||||
|
reserveNode(height, index);
|
||||||
|
reserveNode(height, getBuddy(index));
|
||||||
|
freeNode(height + 1, getParent(index));
|
||||||
|
if((height + 1) < treeHeight)
|
||||||
|
{
|
||||||
|
if(isFree(height + 1, getBuddy(getParent(index))))
|
||||||
|
{
|
||||||
|
return merge(height + 1, getParent(index));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getParent(index);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::getBuddy(size_t index)
|
||||||
|
{
|
||||||
|
return index ^ 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::getParent(size_t index)
|
||||||
|
{
|
||||||
|
return index / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::getChild(size_t index)
|
||||||
|
{
|
||||||
|
return index * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
physaddr_t kernel::BuddyAllocator::nodeToAddress(size_t height, size_t index)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
return index * (blockSize << height);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::BuddyAllocator::addressToNode(size_t height,
|
||||||
|
physaddr_t location) const
|
||||||
|
{
|
||||||
|
return location / (blockSize << height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel::BuddyAllocator::reserveNode(size_t height, size_t index)
|
||||||
|
{
|
||||||
|
size_t bit = (height == 0) ? 0
|
||||||
|
: ((blockCount * 2) - (blockCount >> (height - 1)));
|
||||||
|
bit += index;
|
||||||
|
bitmap[bit / 8] |= 1 << (bit % 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel::BuddyAllocator::freeNode(size_t height, size_t index)
|
||||||
|
{
|
||||||
|
size_t bit = (height == 0) ? 0
|
||||||
|
: ((blockCount * 2) - (blockCount >> (height - 1)));
|
||||||
|
bit += index;
|
||||||
|
bitmap[bit / 8] &= ~(1 << (bit % 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool kernel::BuddyAllocator::isFree(size_t height, size_t index) const
|
||||||
|
{
|
||||||
|
size_t bit = (height == 0) ? 0
|
||||||
|
: ((blockCount * 2) - (blockCount >> (height - 1)));
|
||||||
|
bit += index;
|
||||||
|
char data = bitmap[bit / 8] & (1 << (bit % 8));
|
||||||
|
if(data == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
94
src/buddyallocator.hpp
Executable file
94
src/buddyallocator.hpp
Executable file
@@ -0,0 +1,94 @@
|
|||||||
|
#ifndef BUDDYALLOCATOR_H_
|
||||||
|
#define BUDDYALLOCATOR_H_
|
||||||
|
|
||||||
|
#include "memoryallocator.hpp"
|
||||||
|
#include "memorymap.hpp"
|
||||||
|
|
||||||
|
namespace kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class BuddyAllocator : public MemoryAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
BuddyAllocator();
|
||||||
|
|
||||||
|
BuddyAllocator(MemoryMap& memmap, char* bitmap, size_t blockCount,
|
||||||
|
size_t treeHeight);
|
||||||
|
|
||||||
|
BuddyAllocator(char* bitmap, size_t blockSize, size_t blockCount,
|
||||||
|
size_t treeHeight);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a block of memory containing at least 'size' bytes.
|
||||||
|
* Rounds up to the nearest power of 2 times the size of a block.
|
||||||
|
*/
|
||||||
|
virtual physaddr_t allocate(size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the region of memory starting at 'location' and containing
|
||||||
|
* 'size' bytes.
|
||||||
|
*/
|
||||||
|
virtual void free(physaddr_t location, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the total number of free blocks of memory.
|
||||||
|
*/
|
||||||
|
virtual size_t freeBlocks() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the size in blocks of the largest possible allocation that
|
||||||
|
* will not fail due to lack of memory.
|
||||||
|
*/
|
||||||
|
virtual size_t maxAllocationSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the size in bytes of a single block.
|
||||||
|
*/
|
||||||
|
virtual size_t getBlockSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the total number of blocks managed by this memory
|
||||||
|
* allocator.
|
||||||
|
*/
|
||||||
|
virtual size_t getMemorySize() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static const size_t INVALID = (size_t) -1;
|
||||||
|
|
||||||
|
char* bitmap;
|
||||||
|
|
||||||
|
size_t blockSize;
|
||||||
|
|
||||||
|
size_t blockCount;
|
||||||
|
|
||||||
|
size_t treeHeight;
|
||||||
|
|
||||||
|
size_t findFreeBlock(size_t height);
|
||||||
|
|
||||||
|
size_t split(size_t height, size_t index);
|
||||||
|
|
||||||
|
size_t merge(size_t height, size_t index);
|
||||||
|
|
||||||
|
size_t getBuddy(size_t index);
|
||||||
|
|
||||||
|
size_t getParent(size_t index);
|
||||||
|
|
||||||
|
size_t getChild(size_t index);
|
||||||
|
|
||||||
|
physaddr_t nodeToAddress(size_t height, size_t index) const;
|
||||||
|
|
||||||
|
size_t addressToNode(size_t height, physaddr_t location) const;
|
||||||
|
|
||||||
|
void reserveNode(size_t height, size_t index);
|
||||||
|
|
||||||
|
void freeNode(size_t height, size_t index);
|
||||||
|
|
||||||
|
bool isFree(size_t height, size_t index) const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
0
src/cstring.cpp
Normal file → Executable file
0
src/cstring.cpp
Normal file → Executable file
0
src/cstring.h
Normal file → Executable file
0
src/cstring.h
Normal file → Executable file
190
src/entry.S
Normal file → Executable file
190
src/entry.S
Normal file → Executable file
@@ -1,6 +1,28 @@
|
|||||||
.section .multiboot
|
.section .multiboot
|
||||||
.include "multiboot2header.S"
|
.include "multiboot2header.S"
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
|
||||||
|
gdt:
|
||||||
|
.long 0, 0
|
||||||
|
.short 0xFFFF
|
||||||
|
.short 0x0000
|
||||||
|
.short 0x9A00
|
||||||
|
.short 0x00CF
|
||||||
|
.short 0xFFFF
|
||||||
|
.short 0x0000
|
||||||
|
.short 0x9200
|
||||||
|
.short 0x00CF
|
||||||
|
|
||||||
|
gdt_info:
|
||||||
|
.short 23
|
||||||
|
.long gdt
|
||||||
|
|
||||||
|
.align 16
|
||||||
|
idt_info:
|
||||||
|
.short idt_end - idt - 1
|
||||||
|
.long idt
|
||||||
|
|
||||||
.section .bss
|
.section .bss
|
||||||
|
|
||||||
.align 16
|
.align 16
|
||||||
@@ -14,7 +36,25 @@ _tempPgDir:
|
|||||||
_tempIdentityMap:
|
_tempIdentityMap:
|
||||||
.skip 4096
|
.skip 4096
|
||||||
_tempPgTable:
|
_tempPgTable:
|
||||||
.skip 4096
|
.skip 8192
|
||||||
|
|
||||||
|
_bootCmdLine:
|
||||||
|
.skip 64
|
||||||
|
|
||||||
|
.align 64
|
||||||
|
.global system_info
|
||||||
|
system_info:
|
||||||
|
.skip 16
|
||||||
|
|
||||||
|
.align 64
|
||||||
|
.global memory_map
|
||||||
|
memory_map:
|
||||||
|
.skip 16 * 16
|
||||||
|
|
||||||
|
.global idt
|
||||||
|
idt:
|
||||||
|
.skip 8 * 256
|
||||||
|
idt_end:
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
.global _start
|
.global _start
|
||||||
@@ -25,42 +65,172 @@ _start:
|
|||||||
|
|
||||||
movb $64, 0xB8000
|
movb $64, 0xB8000
|
||||||
|
|
||||||
|
mov $system_info, %edi
|
||||||
|
sub $BASE_DIFF, %edi
|
||||||
|
add $8, %ebx
|
||||||
|
|
||||||
|
switch: mov (%ebx), %eax
|
||||||
|
cmp $0, %eax
|
||||||
|
je s_end
|
||||||
|
cmp $1, %eax
|
||||||
|
je tag_1
|
||||||
|
cmp $4, %eax
|
||||||
|
je tag_4
|
||||||
|
cmp $6, %eax
|
||||||
|
je tag_6
|
||||||
|
cmp $21, %eax
|
||||||
|
je tag_21
|
||||||
|
jmp def
|
||||||
|
|
||||||
|
# Boot command line
|
||||||
|
tag_1: mov 4(%ebx), %ecx
|
||||||
|
sub $8, %ecx
|
||||||
|
mov %ebx, %esi
|
||||||
|
add $8, %esi
|
||||||
|
mov $_bootCmdLine, %edi
|
||||||
|
sub $BASE_DIFF, %edi
|
||||||
|
rep movsb
|
||||||
|
mov $system_info, %edi
|
||||||
|
sub $BASE_DIFF, %edi
|
||||||
|
jmp def
|
||||||
|
|
||||||
|
# Basic memory info
|
||||||
|
tag_4: mov 8(%ebx), %eax
|
||||||
|
mov %eax, (%edi)
|
||||||
|
mov 12(%ebx), %eax
|
||||||
|
mov %eax, 4(%edi)
|
||||||
|
jmp def
|
||||||
|
|
||||||
|
# Memory map
|
||||||
|
tag_6: mov $memory_map, %esi
|
||||||
|
sub $BASE_DIFF, %esi # set esi to point to the table in the kernel image
|
||||||
|
mov 4(%ebx), %ecx
|
||||||
|
sub $16, %ecx # set ecx to store the size of the table provided by the bootloader
|
||||||
|
mov 8(%ebx), %edx # set edx to store the size of each table entry
|
||||||
|
add $16, %ebx # move ebx up to the first entry
|
||||||
|
1: mov (%ebx), %eax
|
||||||
|
mov %eax, (%esi) # save the address of that region in memory
|
||||||
|
mov 8(%ebx), %eax
|
||||||
|
mov %eax, 4(%esi) # save the size of that region in memory
|
||||||
|
mov 16(%ebx), %eax
|
||||||
|
mov %eax, 8(%esi) # save the type of memory in that region
|
||||||
|
add $12, %esi # move esi to the next entry in the kernel's array
|
||||||
|
add %edx, %ebx # move ebx to the next entry in the bootloader's array
|
||||||
|
sub %edx, %ecx # subtract the size of an entry from ecx.
|
||||||
|
jnz 1b # loop if there are entries left
|
||||||
|
mov $0, %eax
|
||||||
|
mov %eax, (%esi)
|
||||||
|
mov %eax, 4(%esi)
|
||||||
|
mov %eax, 8(%esi)
|
||||||
|
jmp switch
|
||||||
|
|
||||||
|
# Program image location
|
||||||
|
tag_21: mov 8(%ebx), %eax
|
||||||
|
mov %eax, 8(%edi)
|
||||||
|
jmp def
|
||||||
|
|
||||||
|
def: mov 4(%ebx), %eax
|
||||||
|
add $7, %eax
|
||||||
|
and $0xFFFFFFF8, %eax
|
||||||
|
add %eax, %ebx
|
||||||
|
jmp switch
|
||||||
|
s_end:
|
||||||
|
|
||||||
|
movb $64, 0xB8002
|
||||||
|
|
||||||
mov $0, %ecx
|
mov $0, %ecx
|
||||||
1: mov %ecx, %eax
|
1:
|
||||||
|
# Generate a page table entry pointing to a page in the kernel binary
|
||||||
|
mov %ecx, %eax
|
||||||
mov $4096, %edx
|
mov $4096, %edx
|
||||||
mul %edx
|
mul %edx
|
||||||
add $PHYSICAL_BASE, %eax
|
|
||||||
or $3, %eax
|
or $3, %eax
|
||||||
|
|
||||||
|
# Load the address of the temporary page table and translate it to a physical address
|
||||||
mov $_tempPgTable, %edi
|
mov $_tempPgTable, %edi
|
||||||
|
sub $BASE_DIFF, %edi
|
||||||
|
|
||||||
|
# Save the PTE into an entry in the temporary page table
|
||||||
mov %eax, (%edi, %ecx, 4)
|
mov %eax, (%edi, %ecx, 4)
|
||||||
|
|
||||||
|
# Load the address of the identity map and translate it to a physical address
|
||||||
mov $_tempIdentityMap, %edi
|
mov $_tempIdentityMap, %edi
|
||||||
mov %eax, 1024(%edi, %ecx, 4)
|
sub $BASE_DIFF, %edi
|
||||||
|
|
||||||
|
# Save the PTE into an entry in the identity map
|
||||||
|
mov %eax, (%edi, %ecx, 4)
|
||||||
|
|
||||||
|
# Increment count and loop
|
||||||
inc %ecx
|
inc %ecx
|
||||||
cmp $IMAGE_SIZE, %ecx
|
mov $IMAGE_SIZE, %edx
|
||||||
|
add $256, %edx
|
||||||
|
cmp %edx, %ecx
|
||||||
jne 1b
|
jne 1b
|
||||||
|
|
||||||
|
# Load the physical address of the identity map, and generate a PDE
|
||||||
mov $_tempIdentityMap, %eax
|
mov $_tempIdentityMap, %eax
|
||||||
|
sub $BASE_DIFF, %eax
|
||||||
or $3, %eax
|
or $3, %eax
|
||||||
mov %eax, (_tempPgDir)
|
|
||||||
|
|
||||||
|
# Load the physical address of the page directory
|
||||||
|
mov $_tempPgDir, %edi
|
||||||
|
sub $BASE_DIFF, %edi
|
||||||
|
|
||||||
|
# Save the PDE to the first element in the page directory
|
||||||
|
mov %eax, (%edi)
|
||||||
|
|
||||||
|
# Load the physical address of the temporary page table, and generate a PDE
|
||||||
mov $_tempPgTable, %eax
|
mov $_tempPgTable, %eax
|
||||||
|
sub $BASE_DIFF, %eax
|
||||||
or $3, %eax
|
or $3, %eax
|
||||||
mov %eax, (_tempPgDir + 3072)
|
|
||||||
|
|
||||||
mov $_tempPgDir, %eax
|
# Save the PDE to the entry corresponding to 0xC0000000
|
||||||
mov %eax, %cr3
|
mov %eax, 3072(%edi)
|
||||||
|
|
||||||
|
# Set the last entry in the page directory to point to the page directory itself
|
||||||
|
mov %edi, %eax
|
||||||
|
or $3, %eax
|
||||||
|
mov %eax, 4092(%edi)
|
||||||
|
|
||||||
|
# Load the physical address of the page directory into CR3
|
||||||
|
mov $_tempPgDir, %edi
|
||||||
|
sub $BASE_DIFF, %edi
|
||||||
|
mov %edi, %cr3
|
||||||
|
|
||||||
|
# Enable paging
|
||||||
mov %cr0, %eax
|
mov %cr0, %eax
|
||||||
or $0x80010000, %eax
|
or $0x80010000, %eax
|
||||||
mov %eax, %cr0
|
mov %eax, %cr0
|
||||||
|
|
||||||
|
# Jump into mapped kernel binary
|
||||||
lea 2f, %eax
|
lea 2f, %eax
|
||||||
jmp *%eax
|
jmp *%eax
|
||||||
2: movl $0, (_tempIdentityMap)
|
2:
|
||||||
|
# Delete PDE corresponding to identity map. We shouldn't need it anymore.
|
||||||
|
movl $0, (_tempIdentityMap)
|
||||||
|
|
||||||
|
# Reload page tables
|
||||||
mov %cr3, %eax
|
mov %cr3, %eax
|
||||||
mov %eax, %cr3
|
mov %eax, %cr3
|
||||||
|
|
||||||
|
# Initialize stack
|
||||||
mov $stackTop, %esp
|
mov $stackTop, %esp
|
||||||
|
lgdt gdt_info
|
||||||
|
lidt idt_info
|
||||||
|
|
||||||
|
jmp $8, $.ldcs
|
||||||
|
.ldcs:
|
||||||
|
mov $16, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %gs
|
||||||
|
mov %ax, %fs
|
||||||
|
mov %ax, %ss
|
||||||
|
|
||||||
|
mov $_bootCmdLine, %eax
|
||||||
|
push %eax
|
||||||
|
|
||||||
|
# Call main function
|
||||||
call main
|
call main
|
||||||
|
|
||||||
_err:
|
_err:
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Error.cpp
|
|
||||||
*
|
|
||||||
* Created on: May 23, 2019
|
|
||||||
* Author: nathan
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "error.h"
|
|
||||||
|
|
||||||
namespace qkernel {
|
|
||||||
|
|
||||||
Error lastError;
|
|
||||||
|
|
||||||
Error::Error()
|
|
||||||
: errorType(ErrorType::none), message("") {}
|
|
||||||
|
|
||||||
Error::Error(ErrorType errorType)
|
|
||||||
: errorType(errorType), message("") {}
|
|
||||||
|
|
||||||
Error::Error(ErrorType errorType, const char* message)
|
|
||||||
: errorType(errorType), message(message) {}
|
|
||||||
|
|
||||||
ErrorType Error::getType()
|
|
||||||
{
|
|
||||||
return errorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* Error::getMessage()
|
|
||||||
{
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* namespace qkernel */
|
|
||||||
40
src/error.h
40
src/error.h
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* Error.h
|
|
||||||
*
|
|
||||||
* Created on: May 23, 2019
|
|
||||||
* Author: nathan
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_ERROR_H_
|
|
||||||
#define SRC_ERROR_H_
|
|
||||||
|
|
||||||
#include "errortype.h"
|
|
||||||
|
|
||||||
namespace qkernel {
|
|
||||||
|
|
||||||
class Error {
|
|
||||||
public:
|
|
||||||
|
|
||||||
Error();
|
|
||||||
|
|
||||||
Error(ErrorType errorType);
|
|
||||||
|
|
||||||
Error(ErrorType errorType, const char* message);
|
|
||||||
|
|
||||||
ErrorType getType();
|
|
||||||
|
|
||||||
const char* getMessage();
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
ErrorType errorType;
|
|
||||||
|
|
||||||
const char* message;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
extern Error lastError;
|
|
||||||
|
|
||||||
} /* namespace qkernel */
|
|
||||||
|
|
||||||
#endif /* SRC_ERROR_H_ */
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* ErrorType.h
|
|
||||||
*
|
|
||||||
* Created on: May 23, 2019
|
|
||||||
* Author: nathan
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef SRC_ERRORTYPE_H_
|
|
||||||
#define SRC_ERRORTYPE_H_
|
|
||||||
|
|
||||||
|
|
||||||
enum class ErrorType
|
|
||||||
{
|
|
||||||
none,
|
|
||||||
outOfBounds,
|
|
||||||
illegalState,
|
|
||||||
outOfMemory,
|
|
||||||
invalidArgument
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* SRC_ERRORTYPE_H_ */
|
|
||||||
9
src/interrupts/Makefile
Normal file
9
src/interrupts/Makefile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
objs = x86/inthandlers.o x86/interruptdescriptor.o x86/idt.o x86/interrupts.o
|
||||||
|
archive = libinterrupts.a
|
||||||
|
|
||||||
|
$(archive): $(objs)
|
||||||
|
i686-elf-ar rcs $@ $^
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f $(archive) $(objs)
|
||||||
19
src/interrupts/interrupts.hpp
Normal file
19
src/interrupts/interrupts.hpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#ifndef INTERRUPTS_H
|
||||||
|
#define INTERRUPTS_H
|
||||||
|
|
||||||
|
namespace kernel
|
||||||
|
{
|
||||||
|
class Interrupts
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
Interrupts();
|
||||||
|
|
||||||
|
void enable();
|
||||||
|
|
||||||
|
void disable();
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
21
src/interrupts/x86/idt.S
Normal file
21
src/interrupts/x86/idt.S
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
.section .bss
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
.global idt
|
||||||
|
idt:
|
||||||
|
.skip 8 * 256
|
||||||
|
idt_end:
|
||||||
|
|
||||||
|
.section .rodata
|
||||||
|
|
||||||
|
.idt_info:
|
||||||
|
.short idt_end - idt - 1
|
||||||
|
.long idt
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
|
||||||
|
.global _lidt
|
||||||
|
.type _lidt, @function
|
||||||
|
_lidt:
|
||||||
|
|
||||||
|
ret
|
||||||
10
src/interrupts/x86/idt.hpp
Normal file
10
src/interrupts/x86/idt.hpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef IDT_H
|
||||||
|
#define IDT_H
|
||||||
|
|
||||||
|
#include "interruptdescriptor.hpp"
|
||||||
|
|
||||||
|
extern kernel::InterruptDescriptor idt[256];
|
||||||
|
|
||||||
|
extern "C" void _lidt();
|
||||||
|
|
||||||
|
#endif
|
||||||
62
src/interrupts/x86/interruptdescriptor.cpp
Normal file
62
src/interrupts/x86/interruptdescriptor.cpp
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#include "interruptdescriptor.hpp"
|
||||||
|
|
||||||
|
kernel::InterruptDescriptor::InterruptDescriptor()
|
||||||
|
{
|
||||||
|
this->m_offset1 = 0;
|
||||||
|
this->m_selector = 0;
|
||||||
|
this->m_zero = 0;
|
||||||
|
this->m_type = 0;
|
||||||
|
this->m_storage = 0;
|
||||||
|
this->m_dpl = 0;
|
||||||
|
this->m_present = 0;
|
||||||
|
this->m_offset2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::InterruptDescriptor::InterruptDescriptor(void* handler, Type type, unsigned int dpl)
|
||||||
|
{
|
||||||
|
uint32_t offset = (uint32_t) handler;
|
||||||
|
this->m_offset1 = (uint16_t) offset;
|
||||||
|
this->m_selector = 8;
|
||||||
|
this->m_zero = 0;
|
||||||
|
this->m_type = (uint16_t) type;
|
||||||
|
this->m_storage = 0;
|
||||||
|
this->m_dpl = dpl;
|
||||||
|
this->m_present = 1;
|
||||||
|
this->m_offset2 = offset >> 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool kernel::InterruptDescriptor::present()
|
||||||
|
{
|
||||||
|
return m_present == 1;
|
||||||
|
}
|
||||||
|
void kernel::InterruptDescriptor::present(bool present)
|
||||||
|
{
|
||||||
|
m_present = present ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::InterruptDescriptor::Type kernel::InterruptDescriptor::type()
|
||||||
|
{
|
||||||
|
return (Type) m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel::InterruptDescriptor::type(kernel::InterruptDescriptor::Type type)
|
||||||
|
{
|
||||||
|
m_type = (unsigned int) type;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int kernel::InterruptDescriptor::dpl()
|
||||||
|
{
|
||||||
|
return m_dpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel::InterruptDescriptor::dpl(unsigned int dpl)
|
||||||
|
{
|
||||||
|
m_dpl = dpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* kernel::InterruptDescriptor::operator=(void* rhs)
|
||||||
|
{
|
||||||
|
uint32_t offset = (uint32_t) rhs;
|
||||||
|
m_offset1 = (uint16_t) offset;
|
||||||
|
m_offset2 = (offset >> 16);
|
||||||
|
}
|
||||||
55
src/interrupts/x86/interruptdescriptor.hpp
Normal file
55
src/interrupts/x86/interruptdescriptor.hpp
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#ifndef INTERRUPTDESCRIPTOR_H
|
||||||
|
#define INTERRUPTDESCRIPTOR_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class InterruptDescriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
TASK32 = 5,
|
||||||
|
TRAP32 = 15,
|
||||||
|
INT32 = 14,
|
||||||
|
TRAP16 = 7,
|
||||||
|
INT16 = 6
|
||||||
|
};
|
||||||
|
|
||||||
|
InterruptDescriptor();
|
||||||
|
|
||||||
|
InterruptDescriptor(void* handler, Type type, unsigned int dpl);
|
||||||
|
|
||||||
|
bool present();
|
||||||
|
|
||||||
|
void present(bool present);
|
||||||
|
|
||||||
|
Type type();
|
||||||
|
|
||||||
|
void type(Type type);
|
||||||
|
|
||||||
|
unsigned int dpl();
|
||||||
|
|
||||||
|
void dpl(unsigned int dpl);
|
||||||
|
|
||||||
|
void* operator=(void* rhs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint16_t m_offset1;
|
||||||
|
uint16_t m_selector;
|
||||||
|
uint16_t m_zero : 8;
|
||||||
|
uint16_t m_type : 4;
|
||||||
|
uint16_t m_storage : 1;
|
||||||
|
uint16_t m_dpl : 2;
|
||||||
|
uint16_t m_present : 1;
|
||||||
|
uint16_t m_offset2;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
19
src/interrupts/x86/interrupts.cpp
Normal file
19
src/interrupts/x86/interrupts.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "../interrupts.hpp"
|
||||||
|
#include "idt.hpp"
|
||||||
|
|
||||||
|
kernel::Interrupts::Interrupts()
|
||||||
|
{
|
||||||
|
// Load interrupt handlers
|
||||||
|
// Configure PIC
|
||||||
|
_lidt();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void kernel::Interrupts::enable()
|
||||||
|
{
|
||||||
|
asm("sti");
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void kernel::Interrupts::disable()
|
||||||
|
{
|
||||||
|
asm("cli");
|
||||||
|
}
|
||||||
32
src/interrupts/x86/inthandlers.cpp
Normal file
32
src/interrupts/x86/inthandlers.cpp
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#include "inthandlers.hpp"
|
||||||
|
|
||||||
|
char* display = (char*) 0xC00B8000;
|
||||||
|
|
||||||
|
__attribute__ ((interrupt))
|
||||||
|
void divisionByZero(void* frame)
|
||||||
|
{
|
||||||
|
*display = 'z';
|
||||||
|
display += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((interrupt))
|
||||||
|
void gpFaultHandler(void* frame, unsigned int error)
|
||||||
|
{
|
||||||
|
*display = 'a';
|
||||||
|
asm("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((interrupt))
|
||||||
|
void pageFaultHandler(void* frame, unsigned int error)
|
||||||
|
{
|
||||||
|
*display = '0';
|
||||||
|
//asm("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((interrupt))
|
||||||
|
void doubleFaultHandler(void* frame, unsigned int error)
|
||||||
|
{
|
||||||
|
*display = '#';
|
||||||
|
//asm("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
16
src/interrupts/x86/inthandlers.hpp
Normal file
16
src/interrupts/x86/inthandlers.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef INTHANDLERS_H
|
||||||
|
#define INTHANDLERS_H
|
||||||
|
|
||||||
|
__attribute__ ((interrupt))
|
||||||
|
void divisionByZero(void* frame);
|
||||||
|
|
||||||
|
__attribute__ ((interrupt))
|
||||||
|
void gpFaultHandler(void* frame, unsigned int error);
|
||||||
|
|
||||||
|
__attribute__ ((interrupt))
|
||||||
|
void pageFaultHandler(void* frame, unsigned int error);
|
||||||
|
|
||||||
|
__attribute__ ((interrupt))
|
||||||
|
void doubleFaultHandler(void* frame, unsigned int error);
|
||||||
|
|
||||||
|
#endif
|
||||||
36
src/linker.ld
Executable file
36
src/linker.ld
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0xC0100000;
|
||||||
|
VIRTUAL_BASE = .;
|
||||||
|
PHYSICAL_BASE = 0x100000;
|
||||||
|
BASE_DIFF = VIRTUAL_BASE - PHYSICAL_BASE;
|
||||||
|
|
||||||
|
.text BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.multiboot)
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss BLOCK(4K) : ALIGN(4K)
|
||||||
|
{
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
|
||||||
|
LOAD_START = ADDR(.text) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
||||||
|
LOAD_END = ADDR(.data) + SIZEOF(.data) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
||||||
|
BSS_END = ADDR(.bss) + SIZEOF(.bss) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
||||||
|
IMAGE_SIZE = ((BSS_END - LOAD_START) + (4096 - ((BSS_END - LOAD_START) % 4096))) / 4096;
|
||||||
|
}
|
||||||
0
src/math.cpp
Normal file → Executable file
0
src/math.cpp
Normal file → Executable file
0
src/math.h
Normal file → Executable file
0
src/math.h
Normal file → Executable file
55
src/memoryallocator.hpp
Executable file
55
src/memoryallocator.hpp
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#ifndef __MEMORYALLOCATOR_H_
|
||||||
|
#define __MEMORYALLOCATOR_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "systypes.hpp"
|
||||||
|
|
||||||
|
namespace kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a dymanic memory allocator.
|
||||||
|
*/
|
||||||
|
class MemoryAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate a block of memory containing 'size' bytes. May round up
|
||||||
|
* depending on the implementation.
|
||||||
|
*/
|
||||||
|
virtual physaddr_t allocate(size_t size) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the region of memory starting at 'location' and containing
|
||||||
|
* 'size' bytes.
|
||||||
|
*/
|
||||||
|
virtual void free(physaddr_t location, size_t size) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the total number of free blocks of memory.
|
||||||
|
*/
|
||||||
|
virtual size_t freeBlocks() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the size in blocks of the largest possible allocation that
|
||||||
|
* will not fail due to lack of memory.
|
||||||
|
*/
|
||||||
|
virtual size_t maxAllocationSize() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the size in bytes of a single block.
|
||||||
|
*/
|
||||||
|
virtual size_t getBlockSize() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the total number of blocks managed by this memory
|
||||||
|
* allocator.
|
||||||
|
*/
|
||||||
|
virtual size_t getMemorySize() const = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
38
src/memorymap.cpp
Normal file
38
src/memorymap.cpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include "memorymap.hpp"
|
||||||
|
|
||||||
|
kernel::MemoryMap::MemoryMap(kernel::MemoryMap::Region* map, size_t entries)
|
||||||
|
{
|
||||||
|
this->map = map;
|
||||||
|
this->entries = entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::MemoryMap::Region& kernel::MemoryMap::operator[](size_t index)
|
||||||
|
{
|
||||||
|
return map[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::MemoryMap::size()
|
||||||
|
{
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
physaddr_t kernel::MemoryMap::Region::getLocation()
|
||||||
|
{
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::MemoryMap::Region::getSize()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::MemoryMap::Type kernel::MemoryMap::Region::getType()
|
||||||
|
{
|
||||||
|
return (Type) type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool kernel::MemoryMap::Region::contains(physaddr_t location, size_t size)
|
||||||
|
{
|
||||||
|
return (location >= this->location) &&
|
||||||
|
(location + size <= this->location + this->size);
|
||||||
|
}
|
||||||
61
src/memorymap.hpp
Normal file
61
src/memorymap.hpp
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#ifndef MEMORYMAP_H
|
||||||
|
#define MEMORYMAP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "systypes.hpp"
|
||||||
|
|
||||||
|
namespace kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class MemoryMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
AVAILABLE = 1,
|
||||||
|
ACPI = 3,
|
||||||
|
DEFECTIVE = 5
|
||||||
|
};
|
||||||
|
|
||||||
|
class Region
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
physaddr_t getLocation();
|
||||||
|
|
||||||
|
size_t getSize();
|
||||||
|
|
||||||
|
Type getType();
|
||||||
|
|
||||||
|
bool contains(physaddr_t location, size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
physaddr_t location;
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
uint32_t type;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
MemoryMap(Region* map, size_t entries);
|
||||||
|
|
||||||
|
Region& operator[](size_t index);
|
||||||
|
|
||||||
|
size_t size();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Region* map;
|
||||||
|
|
||||||
|
size_t entries;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
2
src/multiboot2header.S
Normal file → Executable file
2
src/multiboot2header.S
Normal file → Executable file
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
.set tagEntryType, 3
|
.set tagEntryType, 3
|
||||||
.set tagEntrySize, 12
|
.set tagEntrySize, 12
|
||||||
.set tagEntryAddress, _start - (0xC0000000 - 0x100000)
|
.set tagEntryAddress, _start - (0xC0100000 - 0x100000)
|
||||||
|
|
||||||
.set tagModuleAlignType, 6
|
.set tagModuleAlignType, 6
|
||||||
.set tagModuleAlignSize, 8
|
.set tagModuleAlignSize, 8
|
||||||
|
|||||||
142
src/pagetableentry.cpp
Normal file → Executable file
142
src/pagetableentry.cpp
Normal file → Executable file
@@ -5,9 +5,9 @@
|
|||||||
* Author: nathan
|
* Author: nathan
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "pagetableentry.h"
|
#include "pagetableentry.hpp"
|
||||||
|
|
||||||
namespace qkernel {
|
namespace kernel {
|
||||||
|
|
||||||
static_assert(sizeof(PageTableEntry) == 4, "PTE structure is the wrong size!");
|
static_assert(sizeof(PageTableEntry) == 4, "PTE structure is the wrong size!");
|
||||||
|
|
||||||
@@ -26,102 +26,108 @@ PageTableEntry::PageTableEntry() {
|
|||||||
this->physicalAddress = 0;
|
this->physicalAddress = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::getAccessed() const {
|
bool PageTableEntry::getAccessed() const {
|
||||||
return accessed;
|
return accessed == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::getCacheDisable() const {
|
bool PageTableEntry::getCacheDisable() const
|
||||||
return cacheDisable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTableEntry::setCacheDisable(uint32_t cacheDisable)
|
|
||||||
{
|
{
|
||||||
this->cacheDisable = cacheDisable;
|
return cacheDisable == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::getDirty() const {
|
void PageTableEntry::setCacheDisable(bool cacheDisable)
|
||||||
return dirty;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PageTableEntry::getGlobal() const {
|
|
||||||
return global;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTableEntry::setGlobal(uint32_t global)
|
|
||||||
{
|
{
|
||||||
this->global = global;
|
this->cacheDisable = cacheDisable ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::getPat() const {
|
bool PageTableEntry::getDirty() const
|
||||||
return pat;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTableEntry::setPat(uint32_t pat)
|
|
||||||
{
|
{
|
||||||
this->pat = pat;
|
return dirty == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::getPhysicalAddress() const {
|
bool PageTableEntry::getGlobal() const
|
||||||
uint32_t physicalAddress = this->physicalAddress;
|
{
|
||||||
|
return global == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTableEntry::setGlobal(bool global)
|
||||||
|
{
|
||||||
|
this->global = global ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTableEntry::getPat() const
|
||||||
|
{
|
||||||
|
return pat == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTableEntry::setPat(bool pat)
|
||||||
|
{
|
||||||
|
this->pat = pat ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
physaddr_t PageTableEntry::getPhysicalAddress() const {
|
||||||
|
physaddr_t physicalAddress = this->physicalAddress;
|
||||||
return physicalAddress << 12;
|
return physicalAddress << 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::setPhysicalAddress(uint32_t physicalAddress)
|
physaddr_t PageTableEntry::setPhysicalAddress(physaddr_t physicalAddress)
|
||||||
{
|
|
||||||
if(physicalAddress % 4096 == 0)
|
|
||||||
{
|
{
|
||||||
this->physicalAddress = physicalAddress >> 12;
|
this->physicalAddress = physicalAddress >> 12;
|
||||||
return this->physicalAddress;
|
return this->physicalAddress << 12;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
bool PageTableEntry::getPresent() const
|
||||||
{
|
{
|
||||||
this->physicalAddress = !physicalAddress;
|
return present == 1;
|
||||||
return this->physicalAddress;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::getPresent() const {
|
void PageTableEntry::setPresent(bool present)
|
||||||
return present;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTableEntry::setPresent(uint32_t present)
|
|
||||||
{
|
{
|
||||||
this->present = present;
|
this->present = present ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::getRw() const {
|
bool PageTableEntry::getRw() const
|
||||||
return rw;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTableEntry::setRw(uint32_t rw)
|
|
||||||
{
|
{
|
||||||
this->rw = rw;
|
return rw == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::getUsermode() const {
|
void PageTableEntry::setRw(bool rw)
|
||||||
return usermode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PageTableEntry::setUsermode(uint32_t usermode)
|
|
||||||
{
|
{
|
||||||
this->usermode = usermode;
|
this->rw = rw ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t PageTableEntry::getWriteThrough() const {
|
bool PageTableEntry::getUsermode() 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;
|
return usermode == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTableEntry::setUsermode(bool usermode)
|
||||||
|
{
|
||||||
|
this->usermode = usermode ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTableEntry::getWriteThrough() const {
|
||||||
|
return writeThrough == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PageTableEntry::getShared() const
|
||||||
|
{
|
||||||
|
return shared == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTableEntry::setShared(bool shared)
|
||||||
|
{
|
||||||
|
this->shared = shared ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PageTableEntry::setWriteThrough(bool writeThrough)
|
||||||
|
{
|
||||||
|
this->writeThrough = writeThrough ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
physaddr_t PageTableEntry::operator=(physaddr_t rhs)
|
||||||
|
{
|
||||||
|
return setPhysicalAddress(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace qkernel */
|
} /* namespace qkernel */
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_ */
|
|
||||||
58
src/pagetableentry.hpp
Executable file
58
src/pagetableentry.hpp
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* PageTableEntry.h
|
||||||
|
*
|
||||||
|
* Created on: May 22, 2019
|
||||||
|
* Author: nathan
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SRC_PAGETABLEENTRY_H_
|
||||||
|
#define SRC_PAGETABLEENTRY_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "systypes.hpp"
|
||||||
|
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
class PageTableEntry {
|
||||||
|
public:
|
||||||
|
PageTableEntry();
|
||||||
|
bool getAccessed() const;
|
||||||
|
bool getCacheDisable() const;
|
||||||
|
void setCacheDisable(bool cacheDisable);
|
||||||
|
bool getDirty() const;
|
||||||
|
bool getGlobal() const;
|
||||||
|
void setGlobal(bool global);
|
||||||
|
bool getPat() const;
|
||||||
|
void setPat(bool pat);
|
||||||
|
physaddr_t getPhysicalAddress() const;
|
||||||
|
physaddr_t setPhysicalAddress(physaddr_t physicalAddress);
|
||||||
|
bool getPresent() const;
|
||||||
|
void setPresent(bool present);
|
||||||
|
bool getRw() const;
|
||||||
|
void setRw(bool rw);
|
||||||
|
bool getShared() const;
|
||||||
|
void setShared(bool shared);
|
||||||
|
bool getUsermode() const;
|
||||||
|
void setUsermode(bool usermode);
|
||||||
|
bool getWriteThrough() const;
|
||||||
|
void setWriteThrough(bool writeThrough);
|
||||||
|
physaddr_t operator=(physaddr_t rhs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t present : 1;
|
||||||
|
uint32_t rw : 1;
|
||||||
|
uint32_t usermode : 1;
|
||||||
|
uint32_t writeThrough : 1;
|
||||||
|
uint32_t cacheDisable : 1;
|
||||||
|
uint32_t accessed : 1;
|
||||||
|
uint32_t dirty : 1;
|
||||||
|
uint32_t pat : 1;
|
||||||
|
uint32_t global : 1;
|
||||||
|
uint32_t shared : 1;
|
||||||
|
uint32_t ignored : 2;
|
||||||
|
uint32_t physicalAddress : 20;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace qkernel */
|
||||||
|
|
||||||
|
#endif /* SRC_PAGETABLEENTRY_H_ */
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
/*
|
|
||||||
* PhysicalMemoryAllocator.cpp
|
|
||||||
*
|
|
||||||
* Created on: May 23, 2019
|
|
||||||
* Author: nathan
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "physicalmemoryallocator.h"
|
|
||||||
#include "math.h"
|
|
||||||
#include "error.h"
|
|
||||||
|
|
||||||
namespace qkernel {
|
|
||||||
|
|
||||||
void* const PhysicalMemoryAllocator::nullPtr = (void*) -1;
|
|
||||||
|
|
||||||
PhysicalMemoryAllocator::PhysicalMemoryAllocator()
|
|
||||||
{
|
|
||||||
for(size_t i = 0; i <= treeHeight; i++)
|
|
||||||
{
|
|
||||||
memoryMaps[i] = Bitmap<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 */
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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/pio.S
Normal file
13
src/pio.S
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
.global outb
|
||||||
|
outb:
|
||||||
|
mov 4(%esp), %dx
|
||||||
|
mov 8(%esp), %al
|
||||||
|
out %al, %dx
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global inb
|
||||||
|
inb:
|
||||||
|
mov 4(%esp), %dx
|
||||||
|
xor %eax, %eax
|
||||||
|
in %dx, %al
|
||||||
|
ret
|
||||||
8
src/pio.hpp
Normal file
8
src/pio.hpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef PIO_H
|
||||||
|
#define PIO_H
|
||||||
|
|
||||||
|
extern "C" void outb(short port, char data);
|
||||||
|
|
||||||
|
extern "C" char inb(short port);
|
||||||
|
|
||||||
|
#endif
|
||||||
43
src/quarkkernel.cpp
Normal file → Executable file
43
src/quarkkernel.cpp
Normal file → Executable file
@@ -1,13 +1,42 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#if __STDC_HOSTED__ == 1 || __i686__ != 1
|
#include "systypes.hpp"
|
||||||
#error "ERROR: This program must be compiled for a freestanding environment, and currently only supports the i686 target."
|
#include "systeminfo.hpp"
|
||||||
#endif
|
#include "memorymap.hpp"
|
||||||
|
#include "buddyallocator.hpp"
|
||||||
|
#include "addressspace.hpp"
|
||||||
|
#include "pio.hpp"
|
||||||
|
#include "tty.h"
|
||||||
|
|
||||||
void main()
|
using namespace kernel;
|
||||||
|
|
||||||
|
extern SystemInfo system_info;
|
||||||
|
extern MemoryMap::Region memory_map;
|
||||||
|
|
||||||
|
extern "C" void __cxa_pure_virtual()
|
||||||
{
|
{
|
||||||
int x = 2;
|
|
||||||
x -= 1;
|
}
|
||||||
return;
|
|
||||||
|
void main(char* cmdline)
|
||||||
|
{
|
||||||
|
TTY tty((char*) 0xC00B8000);
|
||||||
|
tty << "--Quark Kernel--\n";
|
||||||
|
tty << "Low memory: \t" << (int) system_info.getLowMemory() << " KiB\n";
|
||||||
|
tty << "High memory:\t" << (int) system_info.getHighMemory() << " KiB\n";
|
||||||
|
tty << "Type\t\tLocation\t\tSize\n";
|
||||||
|
MemoryMap memmap(&memory_map, 16);
|
||||||
|
for(size_t i = 0; i < memmap.size() && memmap[i].getSize() > 0; i++)
|
||||||
|
{
|
||||||
|
tty << (int) memmap[i].getType() << "\t\t\t";
|
||||||
|
tty << (void*) memmap[i].getLocation() << "\t\t";
|
||||||
|
tty << (int) memmap[i].getSize() << "\n";
|
||||||
|
}
|
||||||
|
BuddyAllocator alloc(memmap, (char*) 0xC0000000, system_info.getHighMemory() / 4 + 256, 6);
|
||||||
|
AddressSpace vmem(alloc);
|
||||||
|
vmem.mmap((void*) 0x80000000, 0x10000);
|
||||||
|
outb(0xa1, 0xff);
|
||||||
|
outb(0x21, 0xff);
|
||||||
|
tty << "Nothing left to do. Hanging.\n";
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/systeminfo.cpp
Normal file
16
src/systeminfo.cpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#include "systeminfo.hpp"
|
||||||
|
|
||||||
|
size_t kernel::SystemInfo::getLowMemory()
|
||||||
|
{
|
||||||
|
return lowMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::SystemInfo::getHighMemory()
|
||||||
|
{
|
||||||
|
return highMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
physaddr_t kernel::SystemInfo::getKernelBase()
|
||||||
|
{
|
||||||
|
return kernelBase;
|
||||||
|
}
|
||||||
33
src/systeminfo.hpp
Normal file
33
src/systeminfo.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef SYSTEMINFO_H
|
||||||
|
#define SYSTEMINFO_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "systypes.hpp"
|
||||||
|
|
||||||
|
namespace kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class SystemInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
size_t getLowMemory();
|
||||||
|
|
||||||
|
size_t getHighMemory();
|
||||||
|
|
||||||
|
physaddr_t getKernelBase();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
size_t lowMemory;
|
||||||
|
|
||||||
|
size_t highMemory;
|
||||||
|
|
||||||
|
physaddr_t kernelBase;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
9
src/systypes.hpp
Normal file
9
src/systypes.hpp
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef SYSTYPES_H
|
||||||
|
#define SYSTYPES_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
typedef uint32_t physaddr_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
125
src/tty.cpp
Normal file
125
src/tty.cpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include "tty.h"
|
||||||
|
|
||||||
|
kernel::TTY::TTY(char* vga)
|
||||||
|
{
|
||||||
|
this->vga = vga;
|
||||||
|
this->cursor = 0;
|
||||||
|
this->width = 0;
|
||||||
|
this->base = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::TTY& kernel::TTY::operator<<(kernel::TTY::Format fmt)
|
||||||
|
{
|
||||||
|
switch(fmt)
|
||||||
|
{
|
||||||
|
case Binary:
|
||||||
|
base = 2;
|
||||||
|
break;
|
||||||
|
case Decimal:
|
||||||
|
base = 10;
|
||||||
|
break;
|
||||||
|
case Hex:
|
||||||
|
base = 16;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::TTY& kernel::TTY::operator<<(const char* str)
|
||||||
|
{
|
||||||
|
return printString(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::TTY& kernel::TTY::operator<<(unsigned int n)
|
||||||
|
{
|
||||||
|
return printNumber(n, base, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::TTY& kernel::TTY::operator<<(int n)
|
||||||
|
{
|
||||||
|
return printNumber((unsigned int) n, base, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::TTY& kernel::TTY::operator<<(void* n)
|
||||||
|
{
|
||||||
|
return printNumber((unsigned int) n, 16, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::TTY& kernel::TTY::operator<<(char c)
|
||||||
|
{
|
||||||
|
return putChar(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel::TTY::setWidth(size_t width)
|
||||||
|
{
|
||||||
|
this->width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t kernel::TTY::getWidth()
|
||||||
|
{
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void kernel::TTY::clear()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 80*25; i++)
|
||||||
|
{
|
||||||
|
vga[i * 2] = ' ';
|
||||||
|
}
|
||||||
|
cursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::TTY& kernel::TTY::printNumber(unsigned int n, size_t base,
|
||||||
|
size_t width)
|
||||||
|
{
|
||||||
|
const char* digits = "0123456789ABCDEF";
|
||||||
|
char str[33];
|
||||||
|
size_t i = 1;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
str[i] = digits[n % base];
|
||||||
|
n /= base;
|
||||||
|
i++;
|
||||||
|
} while(n > 0);
|
||||||
|
while(i <= width)
|
||||||
|
{
|
||||||
|
str[i] = '0';
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
str[0] = '\0';
|
||||||
|
for(char* s = str + (i - 1); *s; s--)
|
||||||
|
{
|
||||||
|
putChar(*s);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::TTY& kernel::TTY::printString(const char* str)
|
||||||
|
{
|
||||||
|
while(*str)
|
||||||
|
{
|
||||||
|
putChar(*str);
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel::TTY& kernel::TTY::putChar(char c)
|
||||||
|
{
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case '\n':
|
||||||
|
cursor = (cursor + 80) - (cursor % 80);
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
cursor = (cursor + 4) - (cursor % 4);
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
cursor -= cursor % 160;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vga[cursor * 2] = c;
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
60
src/tty.h
Normal file
60
src/tty.h
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#ifndef TTY_H_
|
||||||
|
#define TTY_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace kernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class TTY
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum Format
|
||||||
|
{
|
||||||
|
Binary,
|
||||||
|
Decimal,
|
||||||
|
Hex
|
||||||
|
};
|
||||||
|
|
||||||
|
TTY(char* vga);
|
||||||
|
|
||||||
|
TTY& operator<<(Format fmt);
|
||||||
|
|
||||||
|
TTY& operator<<(const char* str);
|
||||||
|
|
||||||
|
TTY& operator<<(unsigned int n);
|
||||||
|
|
||||||
|
TTY& operator<<(int n);
|
||||||
|
|
||||||
|
TTY& operator<<(void* n);
|
||||||
|
|
||||||
|
TTY& operator<<(char c);
|
||||||
|
|
||||||
|
void setWidth(size_t width);
|
||||||
|
|
||||||
|
size_t getWidth();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
TTY& printNumber(unsigned int n, size_t base, size_t width);
|
||||||
|
|
||||||
|
TTY& printString(const char* str);
|
||||||
|
|
||||||
|
TTY& putChar(char c);
|
||||||
|
|
||||||
|
char* vga;
|
||||||
|
|
||||||
|
int cursor;
|
||||||
|
|
||||||
|
size_t width;
|
||||||
|
|
||||||
|
size_t base;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user