Simple physical memory allocator, virtual memory manager

This commit is contained in:
2020-07-09 18:50:13 -05:00
parent d3ba3c1d2a
commit 52c3754305
25 changed files with 795 additions and 316 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ quark.iso
src/*~
*~
rootfs
test/

View File

@@ -1,6 +1,6 @@
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
src/systeminfo.o src/memorymap.o src/entry.o src/quarkkernel.o
link_script = src/linker.ld
quark_bin = qkernel
quark_img = quark.iso
@@ -13,11 +13,11 @@ CPPFLAGS = -ffreestanding -O2 -Wall -fno-exceptions -fno-rtti -ggdb
.PHONY: all
all: $(quark_img)
$(quark_img): bin/$(quark_bin)
$(quark_img): bin/$(quark_bin) rootfs/boot/grub/grub.cfg
cp bin/$(quark_bin) rootfs/apps
grub-mkrescue -o $@ rootfs
bin/$(quark_bin): $(objs)
bin/$(quark_bin): $(objs) $(link_script)
mkdir -p bin/
$(CXX) -o $@ -T $(link_script) -ffreestanding -nostdlib -O0 $^ -lgcc

View File

@@ -1,14 +1,37 @@
#include "addressspace.h"
#include "addressspace.hpp"
qkernel::AddressSpace::AddressSpace(MemoryAllocator& malloc)
: malloc(malloc)
{
this->pageTables = (PageTableEntry*) 0xFFC00000;
this->pageDirectory = (PageTableEntry*) 0xFFFFF000;
}
void* qkernel::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 qkernel::AddressSpace::munmap(void* start, size_t length)
@@ -16,12 +39,13 @@ void qkernel::AddressSpace::munmap(void* start, size_t length)
}
void* qkernel::AddressSpace::getPhysicalAddress(void* virtualAddress) const
physaddr_t qkernel::AddressSpace::getPhysicalAddress(void* virtualAddress)
const
{
size_t index = (size_t) virtualAddress / 4096;
PageTableEntry pte = pageTables[index];
if(pte.getPresent())
return (void*) pte.getPhysicalAddress();
return pte.getPhysicalAddress();
else
return (void*) 0;
return 0;
}

View File

@@ -3,8 +3,9 @@
#include <stddef.h>
#include "memoryallocator.h"
#include "pagetableentry.h"
#include "memoryallocator.hpp"
#include "pagetableentry.hpp"
#include "systypes.hpp"
namespace qkernel {
@@ -17,7 +18,7 @@ public:
void munmap(void* start, size_t length);
void* getPhysicalAddress(void* virtualAddress) const;
physaddr_t getPhysicalAddress(void* virtualAddress) const;
private:
@@ -29,6 +30,11 @@ private:
*/
PageTableEntry* pageTables;
/**
* Array of 1024 PDEs, located at the end of the pageTables array
*/
PageTableEntry* pageDirectory;
};
} /* namespace qkernel */

View File

@@ -1,5 +1,7 @@
#include "buddyallocator.h"
#include "buddyallocator.hpp"
#include "math.h"
#include "systypes.hpp"
#include "memorymap.hpp"
#define roundUp(n, m) ((n % m == 0) ? n : (n + m - (n % m)))
@@ -8,9 +10,41 @@ qkernel::BuddyAllocator::BuddyAllocator()
}
qkernel::BuddyAllocator::BuddyAllocator(void* heapLocation, char* bitmap, size_t blockSize, size_t blockCount, size_t treeHeight)
qkernel::BuddyAllocator::BuddyAllocator(qkernel::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() != qkernel::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;
}
}
}
qkernel::BuddyAllocator::BuddyAllocator(char* bitmap, size_t blockSize,
size_t blockCount, size_t treeHeight)
{
this->heapLocation = heapLocation;
this->bitmap = bitmap;
this->blockSize = blockSize;
this->blockCount = blockCount;
@@ -27,7 +61,7 @@ qkernel::BuddyAllocator::BuddyAllocator(void* heapLocation, char* bitmap, size_t
}
}
void* qkernel::BuddyAllocator::allocate(size_t size)
physaddr_t 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
@@ -49,7 +83,7 @@ void* qkernel::BuddyAllocator::allocate(size_t size)
}
}
void qkernel::BuddyAllocator::free(void* location, size_t size)
void qkernel::BuddyAllocator::free(physaddr_t location, size_t size)
{
size_t height = ilog2(roundUp(size, blockSize) / blockSize, true);
if(height <= treeHeight)
@@ -66,7 +100,7 @@ void qkernel::BuddyAllocator::free(void* location, size_t size)
size_t qkernel::BuddyAllocator::freeBlocks() const
{
size_t count = 0;
for(int j = 0; j < blockCount; j++)
for(size_t j = 0; j < blockCount; j++)
{
if(isFree(0, j))
{
@@ -78,9 +112,9 @@ size_t qkernel::BuddyAllocator::freeBlocks() const
size_t qkernel::BuddyAllocator::maxAllocationSize() const
{
for(int i = treeHeight; i >= 0; i--)
for(size_t i = treeHeight; i >= 0; i--)
{
for(int j = 0; j < (blockCount >> i); j++)
for(size_t j = 0; j < (blockCount >> i); j++)
{
if(isFree(i, j))
{
@@ -96,19 +130,14 @@ size_t qkernel::BuddyAllocator::getBlockSize() const
return blockSize;
}
size_t qkernel::BuddyAllocator::getHeapSize() const
size_t qkernel::BuddyAllocator::getMemorySize() 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++)
for(size_t i = 0; i < (blockCount >> height); i++)
{
if(isFree(height, i))
{
@@ -179,35 +208,38 @@ size_t qkernel::BuddyAllocator::getChild(size_t index)
return index * 2;
}
void* qkernel::BuddyAllocator::nodeToAddress(size_t height, size_t index) const
physaddr_t qkernel::BuddyAllocator::nodeToAddress(size_t height, size_t index)
const
{
char* base = (char*) heapLocation;
return reinterpret_cast<void*>(base + index * (blockSize << height));
return index * (blockSize << height);
}
size_t qkernel::BuddyAllocator::addressToNode(size_t height, void* location) const
size_t qkernel::BuddyAllocator::addressToNode(size_t height,
physaddr_t location) const
{
size_t offset = (char*) location - (char*) heapLocation;
return offset / (blockSize << height);
return location / (blockSize << height);
}
void qkernel::BuddyAllocator::reserveNode(size_t height, size_t index)
{
size_t bit = (height == 0) ? 0 : ((blockCount * 2) - (blockCount >> (height - 1)));
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)));
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)));
size_t bit = (height == 0) ? 0
: ((blockCount * 2) - (blockCount >> (height - 1)));
bit += index;
char data = bitmap[bit / 8] & (1 << (bit % 8));
if(data == 0)

View File

@@ -1,7 +1,8 @@
#ifndef BUDDYALLOCATOR_H_
#define BUDDYALLOCATOR_H_
#include "memoryallocator.h"
#include "memoryallocator.hpp"
#include "memorymap.hpp"
namespace qkernel
{
@@ -12,18 +13,23 @@ public:
BuddyAllocator();
BuddyAllocator(void* heapLocation, char* bitmap, size_t blockSize, size_t blockCount, size_t treeHeight);
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.
* 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);
virtual physaddr_t allocate(size_t size);
/**
* Free the region of memory starting at 'location' and containing 'size' bytes.
* Free the region of memory starting at 'location' and containing
* 'size' bytes.
*/
virtual void free(void* location, size_t size);
virtual void free(physaddr_t location, size_t size);
/**
* @returns the total number of free blocks of memory.
@@ -31,8 +37,8 @@ public:
virtual size_t freeBlocks() const;
/**
* @returns the size in blocks of the largest possible allocation that will not
* fail due to lack of memory.
* @returns the size in blocks of the largest possible allocation that
* will not fail due to lack of memory.
*/
virtual size_t maxAllocationSize() const;
@@ -42,21 +48,15 @@ public:
virtual size_t getBlockSize() const;
/**
* @returns the total number of blocks managed by this memory allocator.
* @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;
virtual size_t getMemorySize() const;
private:
static const size_t INVALID = (size_t) -1;
void* heapLocation;
char* bitmap;
size_t blockSize;
@@ -77,9 +77,9 @@ private:
size_t getChild(size_t index);
void* nodeToAddress(size_t height, size_t index) const;
physaddr_t nodeToAddress(size_t height, size_t index) const;
size_t addressToNode(size_t height, void* location) const;
size_t addressToNode(size_t height, physaddr_t location) const;
void reserveNode(size_t height, size_t index);

View File

@@ -1,6 +1,12 @@
.section .multiboot
.include "src/multiboot2header.S"
.section .rodata
idt_info:
.short idt_end - idt - 1
.long idt
.section .bss
.align 16
@@ -16,6 +22,24 @@ _tempIdentityMap:
_tempPgTable:
.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
.global _start
.type _start, @function
@@ -25,13 +49,85 @@ _start:
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
1:
# Generate a page table entry pointing to a page in the kernel binary
mov %ecx, %eax
mov $4096, %edx
mul %edx
add $PHYSICAL_BASE, %eax
or $3, %eax
# Load the address of the temporary page table and translate it to a physical address
@@ -46,11 +142,13 @@ _start:
sub $BASE_DIFF, %edi
# Save the PTE into an entry in the identity map
mov %eax, 1024(%edi, %ecx, 4)
mov %eax, (%edi, %ecx, 4)
# Increment count and loop
inc %ecx
cmp $IMAGE_SIZE, %ecx
mov $IMAGE_SIZE, %edx
add $256, %edx
cmp %edx, %ecx
jne 1b
# Load the physical address of the identity map, and generate a PDE
@@ -73,19 +171,10 @@ _start:
# Save the PDE to the entry corresponding to 0xC0000000
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)
mov %edi, %eax
or $3, %eax
mov %eax, 4092(%edi)
# Load the physical address of the page directory into CR3
mov $_tempPgDir, %edi
@@ -111,7 +200,10 @@ _start:
# Initialize stack
mov $stackTop, %esp
push %ebx
lidt idt_info
mov $_bootCmdLine, %eax
push %eax
# Call main function
call main

View File

@@ -0,0 +1,41 @@
#include "interruptdescriptor.hpp"
qkernel::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;
}
qkernel::InterruptDescriptor::InterruptDescriptor(void* handler,
Type type, unsigned int dpl)
{
uint32_t offset = (uint32_t) handler;
this->m_offset1 = (uint16_t) offset;
this->m_selector = 1;
this->m_zero = 0;
this->m_type = (uint16_t) type;
this->m_storage = 0;
this->m_dpl = dpl;
this->m_present = 0;
this->m_offset = (uint16_t) (offset >> 16);
}
bool qkernel::InterruptDescriptor::present()
{
return m_present == 1;
}
void qkernel::InterruptDescriptor::present(bool present)
{
m_present = present ? 1 : 0;
}
Type qkernel::InterruptDescriptor::type()
{
}

View File

@@ -0,0 +1,52 @@
#ifndef INTERRUPTDESCRIPTOR_H
#define INTERRUPTDESCRIPTOR_H
#include <stdint.h>
namespace qkernel
{
class InterruptDescriptor
{
public:
enum Type
{
TASK32 = 5,
TRAP32 = 15,
INT32 = 14,
TRAP16 = 7,
INT16 = 6
};
InterruptDescriptor();
InterruptDescriptor(void* handler, unsigned int type, unsigned int dpl);
bool present();
void present(bool present);
Type type();
void type(Type type);
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

17
src/inthandlers.cpp Normal file
View File

@@ -0,0 +1,17 @@
#include "inthandlers.hpp"
extern "C"
__attribute__ ((interrupt))
void gpFaultHandler(void* frame, unsigned int error)
{
}
extern "C"
__attribute__ ((interrupt))
void pageFaultHandler(unsigned int error)
{
}
}

12
src/inthandlers.hpp Normal file
View File

@@ -0,0 +1,12 @@
#ifndef INTHANDLERS_H
#define INTHANDLERS_H
extern "C"
__attribute__ ((interrupt))
void gpFaultHandler(void* frame, unsigned int error);
extern "C"
__attribute__ ((interrupt))
void pageFaultHandler(void* frame, unsigned int error);
#endif

View File

@@ -2,7 +2,7 @@ ENTRY(_start)
SECTIONS
{
. = 0xC0000000;
. = 0xC0100000;
VIRTUAL_BASE = .;
PHYSICAL_BASE = 0x100000;
BASE_DIFF = VIRTUAL_BASE - PHYSICAL_BASE;

View File

@@ -2,6 +2,7 @@
#define __MEMORYALLOCATOR_H_
#include <stddef.h>
#include "systypes.hpp"
namespace qkernel
{
@@ -17,12 +18,13 @@ public:
* Allocate a block of memory containing 'size' bytes. May round up
* depending on the implementation.
*/
virtual void* allocate(size_t size) = 0;
virtual physaddr_t allocate(size_t size) = 0;
/**
* Free the region of memory starting at 'location' and containing 'size' bytes.
* Free the region of memory starting at 'location' and containing
* 'size' bytes.
*/
virtual void free(void* location, size_t size) = 0;
virtual void free(physaddr_t location, size_t size) = 0;
/**
* @returns the total number of free blocks of memory.
@@ -30,8 +32,8 @@ public:
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.
* @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;
@@ -41,15 +43,10 @@ public:
virtual size_t getBlockSize() const = 0;
/**
* @returns the total number of blocks managed by this memory allocator.
* @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;
virtual size_t getMemorySize() const = 0;
};

38
src/memorymap.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include "memorymap.hpp"
qkernel::MemoryMap::MemoryMap(qkernel::MemoryMap::Region* map, size_t entries)
{
this->map = map;
this->entries = entries;
}
qkernel::MemoryMap::Region& qkernel::MemoryMap::operator[](size_t index)
{
return map[index];
}
size_t qkernel::MemoryMap::size()
{
return entries;
}
physaddr_t qkernel::MemoryMap::Region::getLocation()
{
return location;
}
size_t qkernel::MemoryMap::Region::getSize()
{
return size;
}
qkernel::MemoryMap::Type qkernel::MemoryMap::Region::getType()
{
return (Type) type;
}
bool qkernel::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
View File

@@ -0,0 +1,61 @@
#ifndef MEMORYMAP_H
#define MEMORYMAP_H
#include <stdint.h>
#include <stddef.h>
#include "systypes.hpp"
namespace qkernel
{
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

View File

@@ -28,7 +28,7 @@
.set tagEntryType, 3
.set tagEntrySize, 12
.set tagEntryAddress, _start - (0xC0000000 - 0x100000)
.set tagEntryAddress, _start - (0xC0100000 - 0x100000)
.set tagModuleAlignType, 6
.set tagModuleAlignSize, 8

View File

@@ -5,7 +5,7 @@
* Author: nathan
*/
#include "pagetableentry.h"
#include "pagetableentry.hpp"
namespace qkernel {
@@ -26,102 +26,108 @@ PageTableEntry::PageTableEntry() {
this->physicalAddress = 0;
}
uint32_t PageTableEntry::getAccessed() const {
return accessed;
bool PageTableEntry::getAccessed() const {
return accessed == 1;
}
uint32_t PageTableEntry::getCacheDisable() const {
return cacheDisable;
}
void PageTableEntry::setCacheDisable(uint32_t cacheDisable)
bool PageTableEntry::getCacheDisable() const
{
this->cacheDisable = cacheDisable;
return cacheDisable == 1;
}
uint32_t PageTableEntry::getDirty() const {
return dirty;
}
uint32_t PageTableEntry::getGlobal() const {
return global;
}
void PageTableEntry::setGlobal(uint32_t global)
void PageTableEntry::setCacheDisable(bool cacheDisable)
{
this->global = global;
this->cacheDisable = cacheDisable ? 1 : 0;
}
uint32_t PageTableEntry::getPat() const {
return pat;
}
void PageTableEntry::setPat(uint32_t pat)
bool PageTableEntry::getDirty() const
{
this->pat = pat;
return dirty == 1;
}
uint32_t PageTableEntry::getPhysicalAddress() const {
uint32_t physicalAddress = this->physicalAddress;
bool PageTableEntry::getGlobal() const
{
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;
}
uint32_t PageTableEntry::setPhysicalAddress(uint32_t physicalAddress)
physaddr_t PageTableEntry::setPhysicalAddress(physaddr_t physicalAddress)
{
if(physicalAddress % 4096 == 0)
{
this->physicalAddress = physicalAddress >> 12;
return this->physicalAddress;
}
else
{
this->physicalAddress = !physicalAddress;
return this->physicalAddress;
}
this->physicalAddress = physicalAddress >> 12;
return this->physicalAddress << 12;
}
uint32_t PageTableEntry::getPresent() const {
return present;
}
void PageTableEntry::setPresent(uint32_t present)
bool PageTableEntry::getPresent() const
{
this->present = present;
return present == 1;
}
uint32_t PageTableEntry::getRw() const {
return rw;
}
void PageTableEntry::setRw(uint32_t rw)
void PageTableEntry::setPresent(bool present)
{
this->rw = rw;
this->present = present ? 1 : 0;
}
uint32_t PageTableEntry::getUsermode() const {
return usermode;
}
void PageTableEntry::setUsermode(uint32_t usermode)
bool PageTableEntry::getRw() const
{
this->usermode = usermode;
return rw == 1;
}
uint32_t PageTableEntry::getWriteThrough() const {
return writeThrough;
}
uint32_t PageTableEntry::getShared() const {
return shared;
}
void PageTableEntry::setShared(uint32_t shared) {
this->shared = shared;
}
void PageTableEntry::setWriteThrough(uint32_t writeThrough)
void PageTableEntry::setRw(bool rw)
{
this->writeThrough = writeThrough;
this->rw = rw ? 1 : 0;
}
bool PageTableEntry::getUsermode() const
{
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 */

View File

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

View File

@@ -1,24 +1,39 @@
#include <stddef.h>
#include <stdint.h>
#include "systypes.hpp"
#include "systeminfo.hpp"
#include "memorymap.hpp"
#include "buddyallocator.hpp"
#include "addressspace.hpp"
#include "tty.h"
#if __STDC_HOSTED__ == 1 || __i686__ != 1
#error "ERROR: This program must be compiled for a freestanding environment, and currently only supports the i686 target."
#endif
#include "buddyallocator.h"
using namespace qkernel;
void main(void* bootInfo)
extern SystemInfo system_info;
extern MemoryMap::Region memory_map;
void main(char* cmdline)
{
char* vga = (char*) 0xC0400000;
TTY tty(vga);
TTY tty((char*) 0xC00B8000);
tty << "--Quark Kernel--\n";
tty << "Successfully enabled paging. Kernel image mapped to 0xC0000000.\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"
<< (void*) memmap[i].getLocation() << "\t\t"
<< (int) memmap[i].getSize() << "\n";
}
BuddyAllocator alloc(memmap, (char*) 0xC0000000,
system_info.getHighMemory() / 4 + 256, 6);
AddressSpace vmem(alloc);
tty << vmem.mmap((void*) 0x80000000, 0x10000) << '\n';
tty << "Nothing left to do. Hanging.\n";
tty << 18542;
char c = 'b';
return;
}

16
src/systeminfo.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include "systeminfo.hpp"
size_t qkernel::SystemInfo::getLowMemory()
{
return lowMemory;
}
size_t qkernel::SystemInfo::getHighMemory()
{
return highMemory;
}
physaddr_t qkernel::SystemInfo::getKernelBase()
{
return kernelBase;
}

33
src/systeminfo.hpp Normal file
View File

@@ -0,0 +1,33 @@
#ifndef SYSTEMINFO_H
#define SYSTEMINFO_H
#include <stddef.h>
#include "systypes.hpp"
namespace qkernel
{
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
View File

@@ -0,0 +1,9 @@
#ifndef SYSTYPES_H
#define SYSTYPES_H
#include <stdint.h>
#include <stddef.h>
typedef uint32_t physaddr_t;
#endif

View File

@@ -5,76 +5,59 @@ qkernel::TTY::TTY(char* vga)
{
this->vga = vga;
this->cursor = 0;
this->width = 0;
this->base = 10;
}
qkernel::TTY& qkernel::TTY::operator<<(qkernel::TTY::Format fmt)
{
switch(fmt)
{
case Binary:
base = 2;
break;
case Decimal:
base = 10;
break;
case Hex:
base = 16;
break;
}
}
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;
return printString(str);
}
qkernel::TTY& qkernel::TTY::operator<<(unsigned int n)
{
return printNumber(n, base, width);
}
qkernel::TTY& qkernel::TTY::operator<<(int n)
{
if(n == 0)
{
operator<<('0');
return *this;
}
return printNumber((unsigned int) n, base, width);
}
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<<(void* n)
{
return printNumber((unsigned int) n, 16, 8);
}
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;
return putChar(c);
}
void qkernel::TTY::setWidth(size_t width)
{
this->width = width;
}
size_t qkernel::TTY::getWidth()
{
return width;
}
void qkernel::TTY::clear()
@@ -86,40 +69,57 @@ void qkernel::TTY::clear()
cursor = 0;
}
qkernel::TTY& qkernel::TTY::printNumber(unsigned int n, int base = 10, bool sign = true, bool leadingZeros = false)
qkernel::TTY& qkernel::TTY::printNumber(unsigned int n, size_t base,
size_t width)
{
if(n == 0)
const char* digits = "0123456789ABCDEF";
char str[33];
size_t i = 1;
do
{
operator<<('0');
return *this;
str[i] = digits[n % base];
n /= base;
i++;
} while(n > 0);
while(i <= width)
{
str[i] = '0';
i++;
}
if(sign)
str[0] = '\0';
for(char* s = str + (i - 1); *s; s--)
{
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;
}
putChar(*s);
}
return *this;
}
qkernel::TTY& qkernel::TTY::printString(const char* str)
{
while(*str)
{
putChar(*str);
str++;
}
return *this;
}
qkernel::TTY& qkernel::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;
}

View File

@@ -1,6 +1,8 @@
#ifndef TTY_H_
#define TTY_H_
#include <stddef.h>
namespace qkernel
{
@@ -8,26 +10,49 @@ 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, int base, bool sign,
bool leadingZeros);
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;
};
}