From 52c3754305ad05a2e82d113ab5dfdfd334710e0c Mon Sep 17 00:00:00 2001 From: Nathan Date: Thu, 9 Jul 2020 18:50:13 -0500 Subject: [PATCH] Simple physical memory allocator, virtual memory manager --- .gitignore | 3 +- Makefile | 6 +- src/addressspace.cpp | 34 +++- src/{addressspace.h => addressspace.hpp} | 12 +- src/buddyallocator.cpp | 80 +++++--- src/{buddyallocator.h => buddyallocator.hpp} | 46 ++--- src/entry.S | 124 +++++++++++-- src/interruptdescriptor.cpp | 41 +++++ src/interruptdescriptor.hpp | 52 ++++++ src/inthandlers.cpp | 17 ++ src/inthandlers.hpp | 12 ++ src/linker.ld | 2 +- ...{memoryallocator.h => memoryallocator.hpp} | 23 +-- src/memorymap.cpp | 38 ++++ src/memorymap.hpp | 61 ++++++ src/multiboot2header.S | 2 +- src/pagetableentry.cpp | 146 ++++++++------- src/pagetableentry.h | 56 ------ src/pagetableentry.hpp | 58 ++++++ src/quarkkernel.cpp | 33 +++- src/systeminfo.cpp | 16 ++ src/systeminfo.hpp | 33 ++++ src/systypes.hpp | 9 + src/tty.cpp | 174 +++++++++--------- src/tty.h | 33 +++- 25 files changed, 795 insertions(+), 316 deletions(-) rename src/{addressspace.h => addressspace.hpp} (65%) rename src/{buddyallocator.h => buddyallocator.hpp} (60%) create mode 100644 src/interruptdescriptor.cpp create mode 100644 src/interruptdescriptor.hpp create mode 100644 src/inthandlers.cpp create mode 100644 src/inthandlers.hpp rename src/{memoryallocator.h => memoryallocator.hpp} (63%) create mode 100644 src/memorymap.cpp create mode 100644 src/memorymap.hpp delete mode 100755 src/pagetableentry.h create mode 100755 src/pagetableentry.hpp create mode 100644 src/systeminfo.cpp create mode 100644 src/systeminfo.hpp create mode 100644 src/systypes.hpp diff --git a/.gitignore b/.gitignore index d0b6b8e..63e9dc8 100755 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ src/*.o quark.iso src/*~ *~ -rootfs \ No newline at end of file +rootfs +test/ \ No newline at end of file diff --git a/Makefile b/Makefile index 77f81a1..e04ac77 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/src/addressspace.cpp b/src/addressspace.cpp index a62b903..d8663c8 100644 --- a/src/addressspace.cpp +++ b/src/addressspace.cpp @@ -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; } diff --git a/src/addressspace.h b/src/addressspace.hpp similarity index 65% rename from src/addressspace.h rename to src/addressspace.hpp index 276a6c7..de5c63e 100755 --- a/src/addressspace.h +++ b/src/addressspace.hpp @@ -3,8 +3,9 @@ #include -#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 */ diff --git a/src/buddyallocator.cpp b/src/buddyallocator.cpp index a2462b0..fb8a60a 100755 --- a/src/buddyallocator.cpp +++ b/src/buddyallocator.cpp @@ -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(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) diff --git a/src/buddyallocator.h b/src/buddyallocator.hpp similarity index 60% rename from src/buddyallocator.h rename to src/buddyallocator.hpp index f14b7a8..2be4b14 100755 --- a/src/buddyallocator.h +++ b/src/buddyallocator.hpp @@ -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. + */ + virtual physaddr_t allocate(size_t size); /** - * Allocate a block of memory containing at least 'size' bytes. Rounds up to the nearest - * power of 2 times the size of a block. + * Free the region of memory starting at 'location' and containing + * 'size' bytes. */ - 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); + 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); diff --git a/src/entry.S b/src/entry.S index 5e8ccf8..92768e1 100755 --- a/src/entry.S +++ b/src/entry.S @@ -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 @@ -72,20 +170,11 @@ _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 diff --git a/src/interruptdescriptor.cpp b/src/interruptdescriptor.cpp new file mode 100644 index 0000000..cbbdf79 --- /dev/null +++ b/src/interruptdescriptor.cpp @@ -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() +{ + +} diff --git a/src/interruptdescriptor.hpp b/src/interruptdescriptor.hpp new file mode 100644 index 0000000..31edfce --- /dev/null +++ b/src/interruptdescriptor.hpp @@ -0,0 +1,52 @@ +#ifndef INTERRUPTDESCRIPTOR_H +#define INTERRUPTDESCRIPTOR_H + +#include + +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 diff --git a/src/inthandlers.cpp b/src/inthandlers.cpp new file mode 100644 index 0000000..f5330b2 --- /dev/null +++ b/src/inthandlers.cpp @@ -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) +{ + +} + +} diff --git a/src/inthandlers.hpp b/src/inthandlers.hpp new file mode 100644 index 0000000..405ad56 --- /dev/null +++ b/src/inthandlers.hpp @@ -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 diff --git a/src/linker.ld b/src/linker.ld index 713d4d7..36695c7 100755 --- a/src/linker.ld +++ b/src/linker.ld @@ -2,7 +2,7 @@ ENTRY(_start) SECTIONS { - . = 0xC0000000; + . = 0xC0100000; VIRTUAL_BASE = .; PHYSICAL_BASE = 0x100000; BASE_DIFF = VIRTUAL_BASE - PHYSICAL_BASE; diff --git a/src/memoryallocator.h b/src/memoryallocator.hpp similarity index 63% rename from src/memoryallocator.h rename to src/memoryallocator.hpp index d420849..b14c8a3 100755 --- a/src/memoryallocator.h +++ b/src/memoryallocator.hpp @@ -2,6 +2,7 @@ #define __MEMORYALLOCATOR_H_ #include +#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; }; diff --git a/src/memorymap.cpp b/src/memorymap.cpp new file mode 100644 index 0000000..96a5fab --- /dev/null +++ b/src/memorymap.cpp @@ -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); +} diff --git a/src/memorymap.hpp b/src/memorymap.hpp new file mode 100644 index 0000000..6a762a7 --- /dev/null +++ b/src/memorymap.hpp @@ -0,0 +1,61 @@ +#ifndef MEMORYMAP_H +#define MEMORYMAP_H + +#include +#include + +#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 diff --git a/src/multiboot2header.S b/src/multiboot2header.S index 8f6f476..44bc2f3 100755 --- a/src/multiboot2header.S +++ b/src/multiboot2header.S @@ -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 diff --git a/src/pagetableentry.cpp b/src/pagetableentry.cpp index 97ceb31..66af515 100755 --- a/src/pagetableentry.cpp +++ b/src/pagetableentry.cpp @@ -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 */ diff --git a/src/pagetableentry.h b/src/pagetableentry.h deleted file mode 100755 index 021b942..0000000 --- a/src/pagetableentry.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * PageTableEntry.h - * - * Created on: May 22, 2019 - * Author: nathan - */ - -#ifndef SRC_PAGETABLEENTRY_H_ -#define SRC_PAGETABLEENTRY_H_ - -#include - -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_ */ diff --git a/src/pagetableentry.hpp b/src/pagetableentry.hpp new file mode 100755 index 0000000..7e7a3f4 --- /dev/null +++ b/src/pagetableentry.hpp @@ -0,0 +1,58 @@ +/* + * PageTableEntry.h + * + * Created on: May 22, 2019 + * Author: nathan + */ + +#ifndef SRC_PAGETABLEENTRY_H_ +#define SRC_PAGETABLEENTRY_H_ + +#include +#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_ */ diff --git a/src/quarkkernel.cpp b/src/quarkkernel.cpp index 9f9cdbc..e9db5f5 100755 --- a/src/quarkkernel.cpp +++ b/src/quarkkernel.cpp @@ -1,24 +1,39 @@ #include #include +#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; } diff --git a/src/systeminfo.cpp b/src/systeminfo.cpp new file mode 100644 index 0000000..889e314 --- /dev/null +++ b/src/systeminfo.cpp @@ -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; +} diff --git a/src/systeminfo.hpp b/src/systeminfo.hpp new file mode 100644 index 0000000..6aedfde --- /dev/null +++ b/src/systeminfo.hpp @@ -0,0 +1,33 @@ +#ifndef SYSTEMINFO_H +#define SYSTEMINFO_H + +#include + +#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 diff --git a/src/systypes.hpp b/src/systypes.hpp new file mode 100644 index 0000000..cf07e96 --- /dev/null +++ b/src/systypes.hpp @@ -0,0 +1,9 @@ +#ifndef SYSTYPES_H +#define SYSTYPES_H + +#include +#include + +typedef uint32_t physaddr_t; + +#endif diff --git a/src/tty.cpp b/src/tty.cpp index 191304d..0ae4832 100644 --- a/src/tty.cpp +++ b/src/tty.cpp @@ -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; } diff --git a/src/tty.h b/src/tty.h index 43dddbf..12327ee 100644 --- a/src/tty.h +++ b/src/tty.h @@ -1,32 +1,57 @@ #ifndef TTY_H_ #define TTY_H_ +#include + namespace qkernel { 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; };