Wrote proper Makefile
This commit is contained in:
9
.gitignore
vendored
Normal file → Executable file
9
.gitignore
vendored
Normal file → Executable file
@@ -1,3 +1,6 @@
|
|||||||
bin/qkernel
|
bin/*
|
||||||
bin/*.o
|
src/*.o
|
||||||
bin/*~
|
quark.iso
|
||||||
|
src/*~
|
||||||
|
*~
|
||||||
|
rootfs
|
||||||
26
Makefile
Normal file
26
Makefile
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
objs = src/addressspace.o src/tty.o src/buddyallocator.o src/math.o \
|
||||||
|
src/cstring.o src/error.o src/pagetableentry.o src/multiboot2header.o\
|
||||||
|
src/entry.o src/quarkkernel.o
|
||||||
|
link_script = src/linker.ld
|
||||||
|
quark_bin = qkernel
|
||||||
|
quark_img = quark.iso
|
||||||
|
|
||||||
|
CXX = i686-elf-g++
|
||||||
|
CC = i686-elf-gcc
|
||||||
|
|
||||||
|
CPPFLAGS = -ffreestanding -O2 -Wall -fno-exceptions -fno-rtti -ggdb
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: $(quark_img)
|
||||||
|
|
||||||
|
$(quark_img): bin/$(quark_bin)
|
||||||
|
cp bin/$(quark_bin) rootfs/apps
|
||||||
|
grub-mkrescue -o $@ rootfs
|
||||||
|
|
||||||
|
bin/$(quark_bin): $(objs)
|
||||||
|
mkdir -p bin/
|
||||||
|
$(CXX) -o $@ -T $(link_script) -ffreestanding -nostdlib -O0 $^ -lgcc
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f $(objs) bin/$(quark_bin) $(quark_img)
|
||||||
16
src/Makefile
16
src/Makefile
@@ -1,16 +0,0 @@
|
|||||||
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)
|
|
||||||
27
src/addressspace.cpp
Normal file
27
src/addressspace.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include "addressspace.h"
|
||||||
|
|
||||||
|
qkernel::AddressSpace::AddressSpace(MemoryAllocator& malloc)
|
||||||
|
: malloc(malloc)
|
||||||
|
{
|
||||||
|
this->pageTables = (PageTableEntry*) 0xFFC00000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* qkernel::AddressSpace::mmap(void* start, size_t length)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void qkernel::AddressSpace::munmap(void* start, size_t length)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void* qkernel::AddressSpace::getPhysicalAddress(void* virtualAddress) const
|
||||||
|
{
|
||||||
|
size_t index = (size_t) virtualAddress / 4096;
|
||||||
|
PageTableEntry pte = pageTables[index];
|
||||||
|
if(pte.getPresent())
|
||||||
|
return (void*) pte.getPhysicalAddress();
|
||||||
|
else
|
||||||
|
return (void*) 0;
|
||||||
|
}
|
||||||
36
src/addressspace.h
Executable file
36
src/addressspace.h
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef SRC_ADDRESSSPACE_H_
|
||||||
|
#define SRC_ADDRESSSPACE_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "memoryallocator.h"
|
||||||
|
#include "pagetableentry.h"
|
||||||
|
|
||||||
|
namespace qkernel {
|
||||||
|
|
||||||
|
class AddressSpace {
|
||||||
|
public:
|
||||||
|
|
||||||
|
AddressSpace(MemoryAllocator& malloc);
|
||||||
|
|
||||||
|
void* mmap(void* start, size_t length);
|
||||||
|
|
||||||
|
void munmap(void* start, size_t length);
|
||||||
|
|
||||||
|
void* 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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace qkernel */
|
||||||
|
|
||||||
|
#endif
|
||||||
0
src/bitmap.h
Normal file → Executable file
0
src/bitmap.h
Normal file → Executable file
221
src/buddyallocator.cpp
Executable file
221
src/buddyallocator.cpp
Executable file
@@ -0,0 +1,221 @@
|
|||||||
|
#include "buddyallocator.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
|
#define roundUp(n, m) ((n % m == 0) ? n : (n + m - (n % m)))
|
||||||
|
|
||||||
|
qkernel::BuddyAllocator::BuddyAllocator()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
qkernel::BuddyAllocator::BuddyAllocator(void* heapLocation, char* bitmap, size_t blockSize, size_t blockCount, size_t treeHeight)
|
||||||
|
{
|
||||||
|
this->heapLocation = heapLocation;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* qkernel::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 qkernel::BuddyAllocator::free(void* 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 qkernel::BuddyAllocator::freeBlocks() const
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
for(int j = 0; j < blockCount; j++)
|
||||||
|
{
|
||||||
|
if(isFree(0, j))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qkernel::BuddyAllocator::maxAllocationSize() const
|
||||||
|
{
|
||||||
|
for(int i = treeHeight; i >= 0; i--)
|
||||||
|
{
|
||||||
|
for(int j = 0; j < (blockCount >> i); j++)
|
||||||
|
{
|
||||||
|
if(isFree(i, j))
|
||||||
|
{
|
||||||
|
return 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qkernel::BuddyAllocator::getBlockSize() const
|
||||||
|
{
|
||||||
|
return blockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qkernel::BuddyAllocator::getHeapSize() const
|
||||||
|
{
|
||||||
|
return blockCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* qkernel::BuddyAllocator::getHeapLocation() const
|
||||||
|
{
|
||||||
|
return heapLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qkernel::BuddyAllocator::findFreeBlock(size_t height)
|
||||||
|
{
|
||||||
|
for(int 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 qkernel::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 qkernel::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 qkernel::BuddyAllocator::getBuddy(size_t index)
|
||||||
|
{
|
||||||
|
return index ^ 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qkernel::BuddyAllocator::getParent(size_t index)
|
||||||
|
{
|
||||||
|
return index / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qkernel::BuddyAllocator::getChild(size_t index)
|
||||||
|
{
|
||||||
|
return index * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* qkernel::BuddyAllocator::nodeToAddress(size_t height, size_t index) const
|
||||||
|
{
|
||||||
|
char* base = (char*) heapLocation;
|
||||||
|
return reinterpret_cast<void*>(base + index * (blockSize << height));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t qkernel::BuddyAllocator::addressToNode(size_t height, void* location) const
|
||||||
|
{
|
||||||
|
size_t offset = (char*) location - (char*) heapLocation;
|
||||||
|
return offset / (blockSize << height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void qkernel::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 qkernel::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 qkernel::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.h
Executable file
94
src/buddyallocator.h
Executable file
@@ -0,0 +1,94 @@
|
|||||||
|
#ifndef BUDDYALLOCATOR_H_
|
||||||
|
#define BUDDYALLOCATOR_H_
|
||||||
|
|
||||||
|
#include "memoryallocator.h"
|
||||||
|
|
||||||
|
namespace qkernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class BuddyAllocator : public MemoryAllocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
BuddyAllocator();
|
||||||
|
|
||||||
|
BuddyAllocator(void* heapLocation, 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 void* allocate(size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the region of memory starting at 'location' and containing 'size' bytes.
|
||||||
|
*/
|
||||||
|
virtual void free(void* 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 getHeapSize() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns a pointer to the beginning of the heap managed by this memory allocator.
|
||||||
|
*/
|
||||||
|
virtual void* getHeapLocation() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static const size_t INVALID = (size_t) -1;
|
||||||
|
|
||||||
|
void* heapLocation;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
void* nodeToAddress(size_t height, size_t index) const;
|
||||||
|
|
||||||
|
size_t addressToNode(size_t height, void* 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
22
src/entry.S
Normal file → Executable file
22
src/entry.S
Normal file → Executable file
@@ -1,5 +1,5 @@
|
|||||||
.section .multiboot
|
.section .multiboot
|
||||||
.include "multiboot2header.S"
|
.include "src/multiboot2header.S"
|
||||||
|
|
||||||
.section .bss
|
.section .bss
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ _tempPgDir:
|
|||||||
_tempIdentityMap:
|
_tempIdentityMap:
|
||||||
.skip 4096
|
.skip 4096
|
||||||
_tempPgTable:
|
_tempPgTable:
|
||||||
.skip 4096
|
.skip 8192
|
||||||
|
|
||||||
.section .text
|
.section .text
|
||||||
.global _start
|
.global _start
|
||||||
@@ -73,7 +73,23 @@ _start:
|
|||||||
# Save the PDE to the entry corresponding to 0xC0000000
|
# Save the PDE to the entry corresponding to 0xC0000000
|
||||||
mov %eax, 3072(%edi)
|
mov %eax, 3072(%edi)
|
||||||
|
|
||||||
|
# Add another PDE for extra mappings the kernel needs
|
||||||
|
add $4096, %eax
|
||||||
|
mov %eax, 3076(%edi)
|
||||||
|
|
||||||
|
# Set the last entry in the page directory to point to the page directory itself
|
||||||
|
or $3, %edi
|
||||||
|
mov %edi, 4092(%edi)
|
||||||
|
|
||||||
|
# Map VGA memory into the address space
|
||||||
|
mov $_tempPgTable, %edi
|
||||||
|
sub $BASE_DIFF, %edi
|
||||||
|
mov $0xB8003, %eax
|
||||||
|
mov %eax, 4096(%edi)
|
||||||
|
|
||||||
# Load the physical address of the page directory into CR3
|
# Load the physical address of the page directory into CR3
|
||||||
|
mov $_tempPgDir, %edi
|
||||||
|
sub $BASE_DIFF, %edi
|
||||||
mov %edi, %cr3
|
mov %edi, %cr3
|
||||||
|
|
||||||
# Enable paging
|
# Enable paging
|
||||||
@@ -95,6 +111,8 @@ _start:
|
|||||||
# Initialize stack
|
# Initialize stack
|
||||||
mov $stackTop, %esp
|
mov $stackTop, %esp
|
||||||
|
|
||||||
|
push %ebx
|
||||||
|
|
||||||
# Call main function
|
# Call main function
|
||||||
call main
|
call main
|
||||||
|
|
||||||
|
|||||||
0
src/error.cpp
Normal file → Executable file
0
src/error.cpp
Normal file → Executable file
0
src/error.h
Normal file → Executable file
0
src/error.h
Normal file → Executable file
0
src/errortype.h
Normal file → Executable file
0
src/errortype.h
Normal file → Executable file
36
src/linker.ld
Executable file
36
src/linker.ld
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0xC0000000;
|
||||||
|
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
58
src/memoryallocator.h
Executable file
58
src/memoryallocator.h
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef __MEMORYALLOCATOR_H_
|
||||||
|
#define __MEMORYALLOCATOR_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
namespace qkernel
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 void* allocate(size_t size) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the region of memory starting at 'location' and containing 'size' bytes.
|
||||||
|
*/
|
||||||
|
virtual void free(void* 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 getHeapSize() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns a pointer to the beginning of the heap managed by this memory allocator.
|
||||||
|
*/
|
||||||
|
virtual void* getHeapLocation() const = 0;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
0
src/multiboot2header.S
Normal file → Executable file
0
src/multiboot2header.S
Normal file → Executable file
0
src/pagetableentry.cpp
Normal file → Executable file
0
src/pagetableentry.cpp
Normal file → Executable file
0
src/pagetableentry.h
Normal file → Executable file
0
src/pagetableentry.h
Normal file → Executable file
@@ -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_ */
|
|
||||||
17
src/quarkkernel.cpp
Normal file → Executable file
17
src/quarkkernel.cpp
Normal file → Executable file
@@ -1,13 +1,24 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "tty.h"
|
||||||
|
|
||||||
#if __STDC_HOSTED__ == 1 || __i686__ != 1
|
#if __STDC_HOSTED__ == 1 || __i686__ != 1
|
||||||
#error "ERROR: This program must be compiled for a freestanding environment, and currently only supports the i686 target."
|
#error "ERROR: This program must be compiled for a freestanding environment, and currently only supports the i686 target."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void main()
|
#include "buddyallocator.h"
|
||||||
|
|
||||||
|
using namespace qkernel;
|
||||||
|
|
||||||
|
void main(void* bootInfo)
|
||||||
{
|
{
|
||||||
int x = 2;
|
char* vga = (char*) 0xC0400000;
|
||||||
x -= 1;
|
TTY tty(vga);
|
||||||
|
tty << "--Quark Kernel--\n";
|
||||||
|
tty << "Successfully enabled paging. Kernel image mapped to 0xC0000000.\n";
|
||||||
|
tty << "Nothing left to do. Hanging.\n";
|
||||||
|
tty << 18542;
|
||||||
|
char c = 'b';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
125
src/tty.cpp
Normal file
125
src/tty.cpp
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include "tty.h"
|
||||||
|
|
||||||
|
qkernel::TTY::TTY(char* vga)
|
||||||
|
{
|
||||||
|
this->vga = vga;
|
||||||
|
this->cursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qkernel::TTY& qkernel::TTY::operator<<(const char* str)
|
||||||
|
{
|
||||||
|
while(*str)
|
||||||
|
{
|
||||||
|
switch(*str)
|
||||||
|
{
|
||||||
|
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] = *str;
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
qkernel::TTY& qkernel::TTY::operator<<(int n)
|
||||||
|
{
|
||||||
|
if(n == 0)
|
||||||
|
{
|
||||||
|
operator<<('0');
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sign = n > 0 ? 1 : -1;
|
||||||
|
if(sign == -1) operator<<('-');
|
||||||
|
|
||||||
|
int quotient;
|
||||||
|
bool showZeros = false;
|
||||||
|
for(int divisor = 1000000000; divisor > 0; divisor /= 10)
|
||||||
|
{
|
||||||
|
quotient = n / divisor;
|
||||||
|
char digit = (char) (sign * (quotient % 10) + '0');
|
||||||
|
if(digit != '0' || showZeros)
|
||||||
|
{
|
||||||
|
operator<<(digit);
|
||||||
|
showZeros = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
qkernel::TTY& qkernel::TTY::operator<<(char c)
|
||||||
|
{
|
||||||
|
switch(c)
|
||||||
|
{
|
||||||
|
case '\n':
|
||||||
|
cursor = (cursor + 160) - (cursor % 160);
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
cursor = (cursor + 8) - (cursor % 8);
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
cursor -= cursor % 160;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vga[cursor * 2] = c;
|
||||||
|
}
|
||||||
|
cursor++;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void qkernel::TTY::clear()
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 80*25; i++)
|
||||||
|
{
|
||||||
|
vga[i * 2] = ' ';
|
||||||
|
}
|
||||||
|
cursor = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qkernel::TTY& qkernel::TTY::printNumber(unsigned int n, int base = 10, bool sign = true, bool leadingZeros = false)
|
||||||
|
{
|
||||||
|
if(n == 0)
|
||||||
|
{
|
||||||
|
operator<<('0');
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sign)
|
||||||
|
{
|
||||||
|
int nSig = (int) n;
|
||||||
|
int sign = nSig > 0 ? 1 : -1;
|
||||||
|
if(sign == -1)
|
||||||
|
{
|
||||||
|
n = (unsigned int) (nSig * sign);
|
||||||
|
operator<<('-');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int initDivisor = (base == 10) ? 1000000000 :
|
||||||
|
((base == 16) ? 0x10000000 :
|
||||||
|
((base == 8) ? 0x40000000 : 0));
|
||||||
|
|
||||||
|
int quotient;
|
||||||
|
bool showZeros = leadingZeros;
|
||||||
|
for(int divisor = 1000000000; divisor > 0; divisor /= base)
|
||||||
|
{
|
||||||
|
quotient = n / divisor;
|
||||||
|
char digit = (char) (sign * (quotient % base) + '0');
|
||||||
|
if(digit != '0' || showZeros)
|
||||||
|
{
|
||||||
|
operator<<(digit);
|
||||||
|
showZeros = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
35
src/tty.h
Normal file
35
src/tty.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef TTY_H_
|
||||||
|
#define TTY_H_
|
||||||
|
|
||||||
|
namespace qkernel
|
||||||
|
{
|
||||||
|
|
||||||
|
class TTY
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
TTY(char* vga);
|
||||||
|
|
||||||
|
TTY& operator<<(const char* str);
|
||||||
|
|
||||||
|
TTY& operator<<(int n);
|
||||||
|
|
||||||
|
TTY& operator<<(char c);
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
TTY& printNumber(unsigned int n, int base, bool sign,
|
||||||
|
bool leadingZeros);
|
||||||
|
|
||||||
|
char* vga;
|
||||||
|
|
||||||
|
int cursor;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user