diff --git a/.gitignore b/.gitignore index e008fba..0db5efa 100755 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ quark-kernel autom4te.cache/ .deps +.dirstamp +.vscode aclocal.m4 ar-lib compile @@ -23,4 +25,5 @@ stamp-h1 *~ rootfs/apps -test/ \ No newline at end of file +test/ +doc/ \ No newline at end of file diff --git a/DEVELOPERS.md b/DEVELOPERS.md new file mode 100644 index 0000000..14db3e1 --- /dev/null +++ b/DEVELOPERS.md @@ -0,0 +1,26 @@ +Notice: The kernel is still in early development. Some information in this file +may be inaccurate. Please create an issue if this is the case. + +# Porting + +The kernel should be portable to most systems, provided they support paging +and have sufficient memory. All platform-specific code belongs in an appropriately-named +subdirectory inside src/. It must provide a linker script, startup code, and +implement a set of functions required by the kernel. + +The linker script must define the following symbols: +- _pageMapLocation The location of the bitmap to be used by the page allocator. +- _heapLocation The location of the kernel's heap. +- _heapSize The size in bytes of the kernel's heap. +- _kernelStart The linear address of the start of the kernel image. +- _kernelEnd The first linear address after the end of the kernel image. + +The startup code is required to enable paging and relocate the kernel if necessary. It also +needs to provide a memory map to the kernel in the form of an array of MemoryMap::Region +structures. It should then call main() with a pointer to the kernel command line as an argument. + +In addition, the contents of mmap.hpp and interrupts.hpp must be implemented. + +# Files + +[TODO] \ No newline at end of file diff --git a/README.md b/README.md index d3c84d7..616b6f2 100755 --- a/README.md +++ b/README.md @@ -1 +1 @@ -===Quark Kernel=== \ No newline at end of file +# Quark Kernel \ No newline at end of file diff --git a/configure.ac b/configure.ac index 639c8f3..6ed9f7e 100644 --- a/configure.ac +++ b/configure.ac @@ -3,19 +3,18 @@ AC_PREREQ([2.69]) AC_INIT([quark-kernel], [pre-alpha]) -AM_INIT_AUTOMAKE([-Wall foreign]) -AC_CONFIG_SRCDIR([src/tty.cpp]) +AM_INIT_AUTOMAKE([-Wall foreign subdir-objects]) +AC_CONFIG_SRCDIR([src/kernel.c]) AC_CONFIG_HEADERS([src/config.h]) # Checks for programs. -AC_PROG_CXX AC_PROG_CC AM_PROG_AS AM_PROG_AR AC_PROG_RANLIB # Checks for header files. -AC_CHECK_HEADERS([stddef.h stdint.h]) +AC_CHECK_HEADERS([stddef.h stdint.h stdarg.h]) # Checks for typedefs, structures, and compiler characteristics. AC_CHECK_HEADER_STDBOOL diff --git a/include/elf.h b/include/elf.h new file mode 100644 index 0000000..6605add --- /dev/null +++ b/include/elf.h @@ -0,0 +1,117 @@ +#pragma once + +#include "types/physaddr.h" +#include + +const uint32_t elf_magic_number = 0x464c457f; + +enum elf_endianness_t +{ + ELF_LITTLE_ENDIAN = 1, + ELF_BIG_ENDIAN = 2 +}; + +enum elf_isa_t +{ + ELF_ISA_NA = 0x00, + ELF_ISA_x86 = 0x03, + ELF_ISA_MIPS = 0x08, + ELF_ISA_PPC = 0x14, + ELF_ISA_PPC64 = 0x15, + ELF_ISA_ARM = 0x28, + ELF_ISA_x86_64 = 0x3E, + ELF_ISA_AARCH64 = 0xB7 +}; + +enum elf_segment_type_t +{ + ELF_UNUSED = 0, + ELF_LOAD = 1, + ELF_DYNAMIC = 2 +}; + +struct elf_file_header_t +{ + uint32_t magic; + char size; + char endianness; + char version; + char abi; + char abi_version; + char reserved[7]; + uint16_t type; + uint16_t machine; + uint32_t _version; + void *entry; +#if defined __i386__ || defined __arm__ + uint32_t phoffset; + uint32_t shoffset; +#elif defined __x86_64__ || defined __aarch64__ + uint64_t phoffset; + uint64_t shoffset; +#endif + uint32_t flags; + uint16_t header_size; + uint16_t phsize; + uint16_t phcount; + uint16_t shsize; + uint16_t shcount; + uint16_t shstrndx; +}; + +struct elf_program_header_t +{ + uint32_t type; +#if defined __i386__ || defined __arm__ + uint32_t offset; + void *vaddr; + physaddr_t paddr; + uint32_t filesize; + uint32_t memsize; + uint32_t flags; + uint32_t align; +#elif defined __x86_64__ || defined __aarch64__ + uint32_t flags; + uint64_t offset; + void *vaddr; + physaddr_t paddr; + uint64_t filesize; + uint64_t memsize; + uint64_t align; +#endif +}; + +struct elf_section_header_t +{ + uint32_t name; + uint32_t type; +#if defined __i386__ || defined __arm__ + uint32_t flags; + void *addr; + uint32_t offset; + uint32_t size; + uint32_t link; + uint32_t info; + uint32_t align; + uint32_t entry_size; +#elif defined __x86_64__ || defined __aarch64__ + uint64_t flags; + void *addr; + uint64_t offset; + uint64_t size; + uint32_t link; + uint32_t info; + uint64_t align; + uint64_t entry_size; +#endif +}; + +#if defined __i386__ + static const elf_isa_t HOST_ISA = ELF_ISA_x86; +#elif defined __x86_64__ + static const elf_isa_t HOST_ISA = ELF_ISA_x86_64; +#elif defined __arm__ + static const elf_isa_t HOST_ISA = ELF_ISA_ARM; +#elif defined __aarch64__ + static const elf_isa_t HOST_ISA = ELF_ISA_AARCH64; +#endif diff --git a/include/kernel.h b/include/kernel.h new file mode 100644 index 0000000..9f6da99 --- /dev/null +++ b/include/kernel.h @@ -0,0 +1,18 @@ +#pragma once + +#include "priorityqueue.h" +#include "module.h" +#include + +struct kernel_t +{ + struct priority_queue_t *priority_queue; +}; + +extern struct kernel_t kernel; + +int do_syscall(struct kernel_t *kernel, size_t id, size_t arg1, size_t arg2, size_t arg3); + +int load_module(struct kernel_t *kernel, struct module_t *module); + +void panic(const char *message) __attribute__ ((noreturn)); diff --git a/include/memorymap.h b/include/memorymap.h new file mode 100644 index 0000000..933b641 --- /dev/null +++ b/include/memorymap.h @@ -0,0 +1,27 @@ +#pragma once + +#include "types/physaddr.h" +#include + +enum memory_type_t +{ + M_AVAILABLE = 1, + M_UNAVAILABLE = 2, + M_DEFECTIVE = 3 +}; + +struct memory_region_t +{ + physaddr_t location; + size_t size; + unsigned int type; +}; + +struct memory_map_t +{ + struct memory_region_t *array; + size_t size; + size_t capacity; +}; + +void insert_region(struct memory_map_t *map, physaddr_t location, size_t size, enum memory_type_t type); \ No newline at end of file diff --git a/include/mmgr.h b/include/mmgr.h new file mode 100644 index 0000000..dc80161 --- /dev/null +++ b/include/mmgr.h @@ -0,0 +1,39 @@ +#pragma once + +#include "pageallocator.h" +#include "types/physaddr.h" + +/** + * @brief Create a new top-level page table and map the kernel in it. + * + * This function does not load the page table; it only initializes it. + * + * @return physaddr_t + */ +physaddr_t create_address_space(struct page_stack_t *page_stack); + +/** + * @brief Load an existing top-level page table + * + * @param table + */ +void load_address_space(physaddr_t table); + +/** + * @brief Maps a single page with the specified flags. + * + * @param page + * @param frame + * @param flags + * @return int + */ +int map_page(struct page_stack_t *page_stack, void *page, physaddr_t frame, int flags); + +/** + * @brief Unmaps a single page, returning the physical address of the frame it + * pointed to. + * + * @param page + * @return physaddr_t + */ +physaddr_t unmap_page(void *page); \ No newline at end of file diff --git a/include/module.h b/include/module.h new file mode 100644 index 0000000..4e0cc1a --- /dev/null +++ b/include/module.h @@ -0,0 +1,10 @@ +#pragma once + +#include "types/physaddr.h" + +struct module_t +{ + physaddr_t start; + physaddr_t end; + char str[64 - 2 * sizeof(physaddr_t)]; +}; \ No newline at end of file diff --git a/include/pageallocator.h b/include/pageallocator.h new file mode 100644 index 0000000..5b52d54 --- /dev/null +++ b/include/pageallocator.h @@ -0,0 +1,75 @@ +#pragma once + +#include "memorymap.h" +#include "types/physaddr.h" +#include + +/** + * @brief Describes a stack containing the physical addresses of available page + * frames. + * + */ +struct page_stack_t +{ + /** + * @brief The total number of physical pages managed by the system. + * + */ + size_t total_pages; + + /** + * @brief Points to the topmost physical address on the stack. + * + */ + physaddr_t *stack_pointer; + + /** + * @brief Points to the bottom of the stack. + * + */ + physaddr_t *base_pointer; + + /** + * @brief Points to the limit of the stack. The stack cannot grow beyond + * this point. + * + */ + physaddr_t *limit_pointer; +}; + +/** + * @brief Pop the topmost address from the stack and returns that value. + * + * If the stack is empty, this function will instead return a status code. This + * can be identified by testing the least signifigant bits of the return value. + * + * @param stack + * @return physaddr_t + */ +physaddr_t reserve_page(struct page_stack_t *stack); + +/** + * @brief Pushes `location` onto the stack. + * + * If there is no room on the stack, the stack will be unaffected. + * + * @param stack + * @param location + */ +int free_page(struct page_stack_t *stack, physaddr_t location); + +/** + * @brief Computes the number of available pages. + * + * @param stack + * @return size_t + */ +size_t free_page_count(struct page_stack_t *stack); + +/** + * @brief Push all available pages in `map` onto the stack + * + * @param stack + * @param map + */ +int initialize_page_stack(struct page_stack_t *stack, struct memory_map_t *map, size_t page_size); diff --git a/include/priorityqueue.h b/include/priorityqueue.h new file mode 100644 index 0000000..85aed7a --- /dev/null +++ b/include/priorityqueue.h @@ -0,0 +1,55 @@ +#pragma once + +#include "process.h" +#include + +/** + * @brief + * + */ +struct priority_queue_t +{ + /** + * @brief A pointer to the heap described by this structure. + * + */ + struct process_t **heap; + + /** + * @brief The current number of elements stored in the heap. + * + */ + size_t size; + + /** + * @brief The maximum number of elements that the heap can currently hold. + * + */ + size_t capacity; +}; + +/** + * @brief + * + * @param queue + * @return struct process_t* + */ +struct process_t *extract_min(struct priority_queue_t *queue); + +/** + * @brief + * + * @param queue + * @param process + * @return int + */ +int insert(struct priority_queue_t *queue, struct process_t *process); + +/** + * @brief + * + * @param queue + * @param process + * @return int + */ +int remove(struct priority_queue_t *queue, struct process_t *process); diff --git a/include/process.h b/include/process.h new file mode 100644 index 0000000..be2bdbf --- /dev/null +++ b/include/process.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +struct process_state_t; + +struct process_t +{ + size_t priority; + + struct process_state_t *state; +}; \ No newline at end of file diff --git a/include/stdio.h b/include/stdio.h new file mode 100644 index 0000000..3c086ee --- /dev/null +++ b/include/stdio.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +int putchar(int c); + +int puts(const char *str); + +int printf(const char *format, ...); + +int sprintf(char *str, const char *format, ...); \ No newline at end of file diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..459eea8 --- /dev/null +++ b/include/string.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +void *memcpy(void *destination, const void *source, size_t num); + +void *memmove(void *destination, const void *source, size_t num); + +int memcmp(const void *ptr1, const void *ptr2, size_t num); + +void *memset(void *ptr, int value, size_t num); + +int strlen(const char *str); + +char *strcpy(char *destination, const char *source); diff --git a/src/systypes.hpp b/include/types/physaddr.h similarity index 71% rename from src/systypes.hpp rename to include/types/physaddr.h index cffce0b..fb00318 100644 --- a/src/systypes.hpp +++ b/include/types/physaddr.h @@ -1,8 +1,6 @@ -#ifndef SYSTYPES_H -#define SYSTYPES_H +#pragma once #include -#include #if defined __i386__ || __arm__ typedef uint32_t physaddr_t; @@ -10,6 +8,4 @@ typedef uint32_t physaddr_t; typedef uint64_t physaddr_t; #else typedef uint64_t physaddr_t; -#endif - -#endif +#endif \ No newline at end of file diff --git a/include/types/status.h b/include/types/status.h new file mode 100644 index 0000000..232f39b --- /dev/null +++ b/include/types/status.h @@ -0,0 +1,9 @@ +#pragma once + +enum status_t +{ + S_OK = 0, + S_BAD_SYSCALL, + S_OUT_OF_MEMORY, + S_OUT_OF_BOUNDS +}; \ No newline at end of file diff --git a/rootfs/boot/grub/grub.cfg b/rootfs/boot/grub/grub.cfg index 1910960..a731acc 100644 --- a/rootfs/boot/grub/grub.cfg +++ b/rootfs/boot/grub/grub.cfg @@ -1,4 +1,3 @@ menuentry "Quark OS" { multiboot2 /apps/quark-kernel - module2 /apps/test } \ No newline at end of file diff --git a/src/Makefile.am b/src/Makefile.am index 4062180..e696654 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,19 +1,20 @@ noinst_PROGRAMS = quark-kernel -quark_kernel_SOURCES = quarkkernel.cpp elf.cpp tty.cpp systeminfo.cpp util.cpp memorymap.cpp buddyallocator.cpp +quark_kernel_SOURCES = kernel.c memorymap.c pageallocator.c priorityqueue.c stdio.c string.c quark_kernel_LDADD = -lgcc -quark_kernel_CPPFLAGS = -ffreestanding -mgeneral-regs-only -O0 -Wall -fno-exceptions -fno-rtti -ggdb +quark_kernel_CFLAGS = -I$(top_srcdir)/include -ffreestanding -mgeneral-regs-only -O0 -Wall -ggdb quark_kernel_LDFLAGS = -nostdlib if x86 -quark_kernel_SOURCES += x86/pagetableentry.cpp \ - x86/mmap.cpp \ - x86/interrupts.cpp \ - x86/inthandlers.cpp \ - x86/interruptdescriptor.cpp \ - x86/idt.S \ - x86/entry.S \ - x86/pio.S \ - x86/multiboot2header.S +quark_kernel_SOURCES += x86/mmgr.c \ + x86/putc.c \ + x86/multiboot2.c \ + x86/interrupts.c \ + x86/apic.c \ + x86/isr.c \ + x86/msr.c \ + x86/quark_x86.c \ + x86/entry.S quark_kernel_LDFLAGS += -T x86/linker.ld quark_kernel_DEPENDENCIES = x86/linker.ld endif + diff --git a/src/allocator.cpp b/src/allocator.cpp new file mode 100644 index 0000000..b7c5bbe --- /dev/null +++ b/src/allocator.cpp @@ -0,0 +1,102 @@ +#include "allocator.hpp" + +#define AVAIL 0 +#define UNAVAIL -1 + +inline size_t ilog2(size_t n) +{ + size_t m = n; + size_t count = 0; + bool isPowerOfTwo = true; + while(m) + { + if((m & 1) == 1 && m > 1) + { + isPowerOfTwo = false; + } + count++; + m >>= 1; + } + return count - (isPowerOfTwo ? 1 : 0); +} + +kernelns::Allocator::Allocator() +{ + +} + +kernelns::Allocator::Allocator(void* base, size_t heapSize, size_t blockSize) +{ + this->base = (char*) base; + this->heapSize = heapSize; + this->blockSize = blockSize; + this->treeHeight = ilog2(heapSize / blockSize); + size_t headerSize = (heapSize / blockSize) << 1; + for(size_t i = 1; i < (heapSize / blockSize) * 2; i++) + this->base[i] = UNAVAIL; + for(size_t i = 0; i < heapSize / blockSize; i++) + { + if(blockSize * i >= headerSize) + { + size_t index = i + (1 << treeHeight); + this->base[index] = AVAIL; + for(; index > 1 && this->base[index ^ 1] == 0; index >>= 1) + { + this->base[index] = UNAVAIL; + this->base[index ^ 1] = UNAVAIL; + this->base[index >> 1] = AVAIL; + } + } + else + { + this->base[i + (1 << treeHeight)] = 1; + } + } +} + +void* kernelns::Allocator::allocate(size_t size) +{ + size += blockSize - 1; + size -= size % blockSize; + size_t height = ilog2(size / blockSize); + size_t index = findFreeBlock(height); + if(index) + { + base[index] = height + 1; + return (void*) ((size_t) base + (blockSize << height) * (index - (1 << (treeHeight - height)))); + } + return NULL; +} + +void kernelns::Allocator::free(void* location) +{ + size_t offset = (size_t) location - (size_t) base; + size_t index = (offset / blockSize) + (1 << treeHeight); + for(; index > 0 && base[index] == UNAVAIL; index >>= 1); + base[index] = AVAIL; + for(; index > 1 && base[index ^ 1] == AVAIL; index >>= 1) + { + base[index] = UNAVAIL; + base[index ^ 1] = UNAVAIL; + base[index >> 1] = AVAIL; + } +} + +size_t kernelns::Allocator::findFreeBlock(size_t height) +{ + if(height > treeHeight) + return 0; + for(size_t index = 1 << (treeHeight - height); index < 1 << (treeHeight - height + 1); index++) + { + if(base[index] == AVAIL) + return index; + } + size_t index = findFreeBlock(height + 1); + if(index) + { + base[index] = UNAVAIL; + base[index << 1] = AVAIL; + base[(index << 1) ^ 1] = AVAIL; + } + return index << 1; +} \ No newline at end of file diff --git a/src/allocator.hpp b/src/allocator.hpp new file mode 100644 index 0000000..d910ff8 --- /dev/null +++ b/src/allocator.hpp @@ -0,0 +1,42 @@ +#ifndef ALLOCATOR_H +#define ALLOCATOR_H + +#include + +namespace kernelns +{ + +class Allocator +{ +public: + + Allocator(); + + /** + * @param base A pointer to the start of the heap. + * @param heapSize The size of the heap, in bytes. Must be a power of two. + * @param blockSize The smallest unit of allocation, in bytes. Must be a power of two less than or equal to heapSize. + */ + Allocator(void* base, size_t heapSize, size_t blockSize); + + void* allocate(size_t size); + + void free(void* location); + +private: + + size_t findFreeBlock(size_t height); + + char* base; + + size_t heapSize; + + size_t blockSize; + + size_t treeHeight; + +}; + +} + +#endif \ No newline at end of file diff --git a/src/buddyallocator.cpp b/src/buddyallocator.cpp deleted file mode 100755 index 93a33c9..0000000 --- a/src/buddyallocator.cpp +++ /dev/null @@ -1,269 +0,0 @@ -#include "buddyallocator.hpp" -#include "systypes.hpp" -#include "memorymap.hpp" - -#define roundUp(n, m) ((n % m == 0) ? n : (n + m - (n % m))) - -uint32_t ilog2(uint32_t n, bool roundUp) -{ - uint32_t m = n; - uint32_t count = 0; - bool isPowerOfTwo = true; - while(m) - { - if((m & 1) == 1 && m > 1) - { - isPowerOfTwo = false; - } - count++; - m >>= 1; - } - return count - (isPowerOfTwo ? 1 : (roundUp ? 0 : 1)); -} - -kernel::BuddyAllocator::BuddyAllocator() -{ - -} - -kernel::BuddyAllocator::BuddyAllocator(kernel::MemoryMap& memmap, - char* bitmap, size_t blockCount, - size_t treeHeight) -{ - this->bitmap = bitmap; - this->blockSize = 4096; - this->blockCount = blockCount; - this->treeHeight = treeHeight; - for(size_t i = 0; i <= treeHeight; i++) - { - for(size_t j = 0; j < (blockCount >> i); j++) - { - reserveNode(i, j); - } - } - physaddr_t location = 0x100000; - for(size_t i = 0; i < memmap.size() && memmap[i].getSize() > 0; i++) - { - if(memmap[i].getType() != kernel::MemoryMap::AVAILABLE) - continue; - if(memmap[i].getLocation() > location) - location = roundUp(memmap[i].getLocation(), 4096); - while(memmap[i].contains(location, 4096)) - { - freeNode(0, location / 4096); - if(isFree(0, getBuddy(location / 4096))) - merge(0, location / 4096); - location += 4096; - } - } -} - -kernel::BuddyAllocator::BuddyAllocator(char* bitmap, size_t blockSize, - size_t blockCount, size_t treeHeight) -{ - this->bitmap = bitmap; - this->blockSize = blockSize; - this->blockCount = blockCount; - this->treeHeight = treeHeight; - for(size_t i = 0; i <= treeHeight; i++) - { - for(size_t j = 0; j < (blockCount >> i); j++) - { - if(i < treeHeight) - reserveNode(i, j); - else - freeNode(i, j); - } - } -} - -physaddr_t kernel::BuddyAllocator::allocate(size_t size) -{ - size_t height = ilog2(roundUp(size, blockSize) / blockSize, true); - if(height > treeHeight) // Requested block size is greater than maximum - { - return 0; - } - else - { - size_t index = findFreeBlock(height); - if(index == INVALID) // Failed to find a big enough free block; out of memory - { - return 0; - } - else - { - reserveNode(height, index); - return nodeToAddress(height, index); - } - } -} - -void kernel::BuddyAllocator::free(physaddr_t location, size_t size) -{ - size_t height = ilog2(roundUp(size, blockSize) / blockSize, true); - if(height <= treeHeight) - { - size_t index = addressToNode(height, location); - freeNode(height, index); - if(isFree(height, getBuddy(index))) - { - merge(height, index); - } - } -} - -size_t kernel::BuddyAllocator::freeBlocks() const -{ - size_t count = 0; - for(size_t j = 0; j < blockCount; j++) - { - if(isFree(0, j)) - { - count++; - } - } - return count; -} - -size_t kernel::BuddyAllocator::maxAllocationSize() const -{ - for(size_t i = treeHeight; i >= 0; i--) - { - for(size_t j = 0; j < (blockCount >> i); j++) - { - if(isFree(i, j)) - { - return 1 << i; - } - } - } - return 0; -} - -size_t kernel::BuddyAllocator::getBlockSize() const -{ - return blockSize; -} - -size_t kernel::BuddyAllocator::getMemorySize() const -{ - return blockCount; -} - -size_t kernel::BuddyAllocator::findFreeBlock(size_t height) -{ - for(size_t i = 0; i < (blockCount >> height); i++) - { - if(isFree(height, i)) - { - return i; - } - } - if(height < treeHeight) - { - size_t parentIndex = findFreeBlock(height + 1); - if(parentIndex != INVALID) - { - return split(height + 1, parentIndex); - } - } - return INVALID; -} - -size_t kernel::BuddyAllocator::split(size_t height, size_t index) -{ - if(height > 0 && isFree(height, index)) - { - reserveNode(height, index); - freeNode(height - 1, getChild(index)); - freeNode(height - 1, getBuddy(getChild(index))); - return getChild(index); - } - else - { - return INVALID; - } -} - -size_t kernel::BuddyAllocator::merge(size_t height, size_t index) -{ - if(isFree(height, index) && isFree(height, getBuddy(index)) && height < treeHeight) - { - reserveNode(height, index); - reserveNode(height, getBuddy(index)); - freeNode(height + 1, getParent(index)); - if((height + 1) < treeHeight) - { - if(isFree(height + 1, getBuddy(getParent(index)))) - { - return merge(height + 1, getParent(index)); - - } - } - return getParent(index); - } - else - { - return INVALID; - } -} - -size_t kernel::BuddyAllocator::getBuddy(size_t index) -{ - return index ^ 1; -} - -size_t kernel::BuddyAllocator::getParent(size_t index) -{ - return index / 2; -} - -size_t kernel::BuddyAllocator::getChild(size_t index) -{ - return index * 2; -} - -physaddr_t kernel::BuddyAllocator::nodeToAddress(size_t height, size_t index) - const -{ - return index * (blockSize << height); -} - -size_t kernel::BuddyAllocator::addressToNode(size_t height, - physaddr_t location) const -{ - return location / (blockSize << height); -} - -void kernel::BuddyAllocator::reserveNode(size_t height, size_t index) -{ - size_t bit = (height == 0) ? 0 - : ((blockCount * 2) - (blockCount >> (height - 1))); - bit += index; - bitmap[bit / 8] |= 1 << (bit % 8); -} - -void kernel::BuddyAllocator::freeNode(size_t height, size_t index) -{ - size_t bit = (height == 0) ? 0 - : ((blockCount * 2) - (blockCount >> (height - 1))); - bit += index; - bitmap[bit / 8] &= ~(1 << (bit % 8)); -} - -bool kernel::BuddyAllocator::isFree(size_t height, size_t index) const -{ - size_t bit = (height == 0) ? 0 - : ((blockCount * 2) - (blockCount >> (height - 1))); - bit += index; - char data = bitmap[bit / 8] & (1 << (bit % 8)); - if(data == 0) - { - return true; - } - else - { - return false; - } -} diff --git a/src/buddyallocator.hpp b/src/buddyallocator.hpp deleted file mode 100755 index d30351f..0000000 --- a/src/buddyallocator.hpp +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef BUDDYALLOCATOR_H_ -#define BUDDYALLOCATOR_H_ - -#include "pageallocator.hpp" -#include "memorymap.hpp" - -namespace kernel -{ - -class BuddyAllocator : public MemoryAllocator -{ -public: - - BuddyAllocator(); - - BuddyAllocator(MemoryMap& memmap, char* bitmap, size_t blockCount, - size_t treeHeight); - - BuddyAllocator(char* bitmap, size_t blockSize, size_t blockCount, - size_t treeHeight); - - /** - * Allocate a block of memory containing at least 'size' bytes. - * Rounds up to the nearest power of 2 times the size of a block. - */ - virtual physaddr_t allocate(size_t size); - - /** - * Free the region of memory starting at 'location' and containing - * 'size' bytes. - */ - virtual void free(physaddr_t location, size_t size); - - /** - * @returns the total number of free blocks of memory. - */ - virtual size_t freeBlocks() const; - - /** - * @returns the size in blocks of the largest possible allocation that - * will not fail due to lack of memory. - */ - virtual size_t maxAllocationSize() const; - - /** - * @returns the size in bytes of a single block. - */ - virtual size_t getBlockSize() const; - - /** - * @returns the total number of blocks managed by this memory - * allocator. - */ - virtual size_t getMemorySize() const; - -private: - - static const size_t INVALID = (size_t) -1; - - char* bitmap; - - size_t blockSize; - - size_t blockCount; - - size_t treeHeight; - - size_t findFreeBlock(size_t height); - - size_t split(size_t height, size_t index); - - size_t merge(size_t height, size_t index); - - size_t getBuddy(size_t index); - - size_t getParent(size_t index); - - size_t getChild(size_t index); - - physaddr_t nodeToAddress(size_t height, size_t index) const; - - size_t addressToNode(size_t height, physaddr_t location) const; - - void reserveNode(size_t height, size_t index); - - void freeNode(size_t height, size_t index); - - bool isFree(size_t height, size_t index) const; - -}; - -} - -#endif diff --git a/src/elf.cpp b/src/elf.cpp deleted file mode 100644 index ff503ab..0000000 --- a/src/elf.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "elf.hpp" -#include "util.hpp" - -kernel::ELF::ELF(void* location) -{ - this->location = location; -} - -void* kernel::ELF::entry() -{ - Header* fileHeader = (Header*) location; - return fileHeader->entry; -} - -int kernel::ELF::validate() -{ - Header* fileHeader = (Header*) location; - if(fileHeader->magic != 0x464c457f) - return -1; - else if((ISA) fileHeader->machine != HOST_ISA) - return -1; - else if((Endianness) fileHeader->endianness != Little) - return -1; - return 0; -} - -int kernel::ELF::load() -{ - Header* fileHeader = (Header*) location; - ProgramHeader* programHeader = (ProgramHeader*) ((size_t) location + fileHeader->phoffset); - int count = (int) fileHeader->phcount; - for(int i = 0; i < count; i++) - { - if((SegmentType) programHeader->type != Load) - continue; - memcpy(programHeader->vaddr, location + programHeader->offset, programHeader->filesize); - } - return 0; -} \ No newline at end of file diff --git a/src/elf.hpp b/src/elf.hpp deleted file mode 100644 index bf62255..0000000 --- a/src/elf.hpp +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef ELF_H -#define ELF_H - -#include - -#include "systypes.hpp" - -namespace kernel -{ - -class ELF -{ -public: - - enum Endianness - { - Little = 1, - Big = 2 - }; - - enum ISA - { - NA = 0x00, - x86 = 0x03, - MIPS = 0x08, - PPC = 0x14, - PPC64 = 0x15, - ARM = 0x28, - x86_64 = 0x3E, - aarch64 = 0xB7 - }; - - enum SegmentType - { - Unused = 0, - Load = 1, - Dynamic = 2 - }; - - struct Header - { - uint32_t magic; - char size; - char endianness; - char version; - char abi; - char abiVersion; - char reserved[7]; - uint16_t type; - uint16_t machine; - uint32_t _version; - void* entry; -#if defined __i386__ || defined __arm__ - uint32_t phoffset; - uint32_t shoffset; -#elif defined __x86_64__ || defined __aarch64__ - uint64_t phoffset; - uint64_t shoffset; -#endif - uint32_t flags; - uint16_t headerSize; - uint16_t phsize; - uint16_t phcount; - uint16_t shsize; - uint16_t shcount; - uint16_t shstrndx; - }; - - struct ProgramHeader - { - uint32_t type; -#if defined __i386__ || defined __arm__ - uint32_t offset; - void* vaddr; - physaddr_t paddr; - uint32_t filesize; - uint32_t memsize; - uint32_t flags; - uint32_t align; -#elif defined __x86_64__ || defined __aarch64__ - uint32_t flags; - uint64_t offset; - void* vaddr; - physaddr_t paddr; - uint64_t filesize; - uint64_t memsize; - uint64_t align; -#endif - }; - - struct SectionHeader - { - uint32_t name; - uint32_t type; -#if defined __i386__ || defined __arm__ - uint32_t flags; - void* addr; - uint32_t offset; - uint32_t size; - uint32_t link; - uint32_t info; - uint32_t align; - uint32_t entrysize; -#elif defined __x86_64__ || defined __aarch64__ - uint64_t flags; - void* addr; - uint64_t offset; - uint64_t size; - uint32_t link; - uint32_t info; - uint64_t align; - uint64_t entrysize; -#endif - }; - -#if defined __i386__ - static const ISA HOST_ISA = x86; -#elif defined __x86_64__ - static const ISA HOST_ISA = x86_64; -#elif defined __arm__ - static const ISA HOST_ISA = ARM; -#elif defined __aarch64__ - static const ISA HOST_ISA = aarch64; -#endif - - ELF(void* location); - - void* entry(); - - int validate(); - - int load(); - -private: - - void* location; - -}; - -} - -#endif \ No newline at end of file diff --git a/src/interrupts.hpp b/src/interrupts.hpp deleted file mode 100644 index 173a002..0000000 --- a/src/interrupts.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef INTERRUPTS_H -#define INTERRUPTS_H - -namespace kernel -{ - class Interrupts - { - public: - - Interrupts(); - - void enable(); - - void disable(); - - }; -} - -#endif \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c new file mode 100644 index 0000000..cf049dc --- /dev/null +++ b/src/kernel.c @@ -0,0 +1,11 @@ +#include "kernel.h" + +int do_syscall(struct kernel_t *kernel, size_t id, size_t arg1, size_t arg2, size_t arg3) +{ + +} + +int load_module(struct kernel_t *kernel, struct module_t *module) +{ + +} \ No newline at end of file diff --git a/src/kernelstate.hpp b/src/kernelstate.hpp deleted file mode 100644 index 7133f9c..0000000 --- a/src/kernelstate.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef KERNELSTATE_H -#define KERNELSTATE_H - -#include - -#include "process.hpp" - -namespace kernel -{ - -class State -{ -public: - - static const size_t MAX_PROCESSES = 2048; - -}; - -} - -#endif \ No newline at end of file diff --git a/src/memorymap.c b/src/memorymap.c new file mode 100644 index 0000000..2adef20 --- /dev/null +++ b/src/memorymap.c @@ -0,0 +1,136 @@ +#include "memorymap.h" +#include + +int compare_regions(struct memory_region_t *lhs, struct memory_region_t *rhs) +{ + if(lhs->location == rhs->location) + { + return lhs->size > rhs->size ? 1 + : (lhs->size == rhs->size ? 0 + : -1); + } + else + { + return lhs->location > rhs->location ? 1 : -1; + } +} + +bool region_overlaps(struct memory_region_t *lhs, struct memory_region_t *rhs) +{ + if(rhs->location < lhs->location) + { + return rhs->location + rhs->size > lhs->location; + } + return rhs->location < lhs->location + lhs->size; +} + +bool region_contains(struct memory_region_t *lhs, struct memory_region_t *rhs) +{ + return (rhs->location >= lhs->location) && + (rhs->location + rhs->size <= lhs->location + lhs->size); +} + +void insert_map_entry(struct memory_map_t *map, physaddr_t location, size_t size, unsigned int type) +{ + struct memory_region_t new_region = {.location = location, .size = size, .type = type}; + unsigned int i = 0; + while(i < map->size) + { + if(compare_regions(&new_region, &map->array[i]) < 0) + { + struct memory_region_t buffer = new_region; + new_region = map->array[i]; + map->array[i] = buffer; + } + i++; + } + map->array[i] = new_region; + map->size++; +} + +void remove_map_entry(struct memory_map_t *map, int index) +{ + if(index >= 0 && index < map->size) + { + for(int i = index; i < map->size - 1; i++) + { + map->array[i] = map->array[i + 1]; + } + map->size--; + } +} + +int trim_map(struct memory_map_t *map, int index) +{ + if(index + 1 >= map->size) + { + return -1; + } + struct memory_region_t left = map->array[index]; + struct memory_region_t right = map->array[index + 1]; + if(region_overlaps(&left, &right)) + { + if(left.type == right.type) + { + left.size = (right.location + right.size > left.location + left.size ? right.location + right.size : left.location + left.size) - left.location; + remove_map_entry(map, index + 1); + return index; + } + else if(left.type < right.type) + { + if(region_contains(&right, &left)) + { + remove_map_entry(map, index); + return index; + } + else if(left.location + left.size <= right.location + right.size) + { + left.size = (right.location > left.location) ? right.location - left.location : 0; + return index + 1; + } + else + { + struct memory_region_t new_right = { + .location = right.location + right.size, + .size = (left.location + left.size) - (right.location + right.size), + .type = left.type}; + left.size = (right.location > left.location) ? right.location - left.location : 0; + if(left.size == 0) + remove_map_entry(map, index); + insert_map_entry(map, new_right.location, new_right.size, new_right.type); + return index + 2; + } + } + else + { + if(region_contains(&left, &right)) + { + remove_map_entry(map, index + 1); + return index; + } + else + { + right.size = (right.location + right.size) - (left.location + left.size); + right.location = left.location + left.size; + return index + 1; + } + } + } + else if((left.location + left.size == right.location) && left.type == right.type) + { + left.size = right.location + right.size - left.location; + remove_map_entry(map, index + 1); + return index; + } + return index + 1; +} + +void insert_region(struct memory_map_t *map, physaddr_t location, size_t size, unsigned int type) +{ + insert_map_entry(map, location, size, type); + int i = 0; + while(i >= 0) + { + i = trim_map(map, i); + } +} \ No newline at end of file diff --git a/src/memorymap.cpp b/src/memorymap.cpp deleted file mode 100644 index 2935778..0000000 --- a/src/memorymap.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "memorymap.hpp" - -kernel::MemoryMap::MemoryMap(kernel::MemoryMap::Region* map, size_t entries) -{ - this->map = map; - this->entries = entries; -} - -kernel::MemoryMap::Region& kernel::MemoryMap::operator[](size_t index) -{ - return map[index]; -} - -size_t kernel::MemoryMap::size() -{ - return entries; -} - -physaddr_t kernel::MemoryMap::Region::getLocation() -{ - return location; -} - -size_t kernel::MemoryMap::Region::getSize() -{ - return size; -} - -kernel::MemoryMap::Type kernel::MemoryMap::Region::getType() -{ - return (Type) type; -} - -bool kernel::MemoryMap::Region::contains(physaddr_t location, size_t size) -{ - return (location >= this->location) && - (location + size <= this->location + this->size); -} diff --git a/src/memorymap.hpp b/src/memorymap.hpp deleted file mode 100644 index 853927a..0000000 --- a/src/memorymap.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef MEMORYMAP_H -#define MEMORYMAP_H - -#include -#include - -#include "systypes.hpp" - -namespace kernel -{ - -class MemoryMap -{ -public: - - enum Type - { - AVAILABLE = 1, - ACPI = 3, - DEFECTIVE = 5 - }; - - class Region - { - public: - - physaddr_t getLocation(); - - size_t getSize(); - - Type getType(); - - bool contains(physaddr_t location, size_t size); - - private: - - physaddr_t location; - - size_t size; - - uint32_t type; - - }; - - MemoryMap(Region* map, size_t entries); - - Region& operator[](size_t index); - - size_t size(); - -private: - - Region* map; - - size_t entries; - -}; - -} - -#endif diff --git a/src/mmap.hpp b/src/mmap.hpp deleted file mode 100644 index 8f354d3..0000000 --- a/src/mmap.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef MMAP_H -#define MMAP_H - -#include "pageallocator.hpp" - -#define MMAP_RW 0x01 -#define MMAP_EXEC 0x02 -#define MMAP_SHARED 0x04 - -namespace kernel -{ - -int mmap(MemoryAllocator& allocator, void* start, size_t length, int flags); - -int munmap(MemoryAllocator& allocator, void* start, size_t length); - -bool isMapped(void* addr); - -physaddr_t getPhysicalAddress(void* addr); - -int createAddressSpace(void* table); - -int loadAddressSpace(physaddr_t table); - -} - -#endif \ No newline at end of file diff --git a/src/mmgr.hpp b/src/mmgr.hpp deleted file mode 100644 index b34b018..0000000 --- a/src/mmgr.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef MMGR_H -#define MMGR_H - -#include "mmap.hpp" -#include "buddyallocator.hpp" - -#endif \ No newline at end of file diff --git a/src/pageallocator.c b/src/pageallocator.c new file mode 100644 index 0000000..6289809 --- /dev/null +++ b/src/pageallocator.c @@ -0,0 +1,52 @@ +#include "pageallocator.h" +#include "types/status.h" + +physaddr_t reserve_page(struct page_stack_t *stack) +{ + if(stack->stack_pointer < stack->base_pointer) + { + physaddr_t frame = *stack->stack_pointer; + *stack->stack_pointer = (physaddr_t) 0; + stack->stack_pointer++; + return frame; + } + return S_OUT_OF_MEMORY; +} + +int free_page(struct page_stack_t *stack, physaddr_t location) +{ + if(stack->stack_pointer > stack->limit_pointer) + { + stack->stack_pointer--; + *stack->stack_pointer = location; + return S_OK; + } + return S_OUT_OF_MEMORY; +} + +size_t free_page_count(struct page_stack_t *stack) +{ + return stack->base_pointer - stack->stack_pointer; +} + +int initialize_page_stack(struct page_stack_t *stack, struct memory_map_t *map, size_t page_size) +{ + stack->total_pages = 0; + for(int i = 0; i < map->size; i++) + { + if(map->array[i].type != M_AVAILABLE) + { + continue; + } + size_t location = (map->array[i].location + page_size - 1) & ~(page_size - 1); + while(location + page_size <= map->array[i].location + map->array[i].size) + { + if(free_page(stack, location) != S_OK) + { + return S_OUT_OF_MEMORY; + } + stack->total_pages++; + location += page_size; + } + } +} diff --git a/src/pageallocator.hpp b/src/pageallocator.hpp deleted file mode 100755 index 48ea87c..0000000 --- a/src/pageallocator.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef __MEMORYALLOCATOR_H_ -#define __MEMORYALLOCATOR_H_ - -#include -#include "systypes.hpp" - -namespace kernel -{ - -/** - * Interface for a dymanic memory allocator. - */ -class MemoryAllocator -{ -public: - - /** - * Allocate a block of memory containing 'size' bytes. May round up - * depending on the implementation. - */ - virtual physaddr_t allocate(size_t size) = 0; - - /** - * Free the region of memory starting at 'location' and containing - * 'size' bytes. - */ - virtual void free(physaddr_t location, size_t size) = 0; - - /** - * @returns the total number of free blocks of memory. - */ - virtual size_t freeBlocks() const = 0; - - /** - * @returns the size in blocks of the largest possible allocation that - * will not fail due to lack of memory. - */ - virtual size_t maxAllocationSize() const = 0; - - /** - * @returns the size in bytes of a single block. - */ - virtual size_t getBlockSize() const = 0; - - /** - * @returns the total number of blocks managed by this memory - * allocator. - */ - virtual size_t getMemorySize() const = 0; - -}; - -} - -#endif diff --git a/src/priorityqueue.c b/src/priorityqueue.c new file mode 100644 index 0000000..5ab2873 --- /dev/null +++ b/src/priorityqueue.c @@ -0,0 +1,67 @@ +#include "priorityqueue.h" +#include "types/status.h" + +void heapify(struct priority_queue_t *queue, size_t i) +{ + if(i * 2 + 1 >= queue->size) + { + return; + } + else if(queue->heap[i * 2 + 1]->priority <= queue->heap[i]->priority + && queue->heap[i * 2 + 1]->priority <= queue->heap[i * 2 + 2]->priority) + { + struct process_t *buffer = queue->heap[i]; + queue->heap[i] = queue->heap[i * 2 + 1]; + queue->heap[i * 2 + 1] = buffer; + heapify(queue, i * 2 + 1); + } + else if(queue->heap[i * 2 + 2]->priority <= queue->heap[i]->priority + && queue->heap[i * 2 + 2]->priority <= queue->heap[i * 2 + 1]->priority) + { + struct process_t *buffer = queue->heap[i]; + queue->heap[i] = queue->heap[i * 2 + 2]; + queue->heap[i * 2 + 2] = buffer; + heapify(queue, i * 2 + 2); + } +} + +struct process_t *extract_min(struct priority_queue_t *queue) +{ + if(queue->size == 0) + return NULL; + queue->size--; + struct process_t *p = queue->heap[0]; + queue->heap[0] = queue->heap[queue->size]; + heapify(queue, 0); + return p; +} + +int insert(struct priority_queue_t *queue, struct process_t *process) +{ + if(queue->size == queue->capacity) + return S_OUT_OF_MEMORY; + size_t i = queue->size; + queue->size++; + while(i > 0 && queue->heap[(i - 1) / 2]->priority > process->priority) + { + queue->heap[i] = queue->heap[(i - 1) / 2]; + i = (i - 1) / 2; + } + queue->heap[i] = process; + return S_OK; +} + +int remove(struct priority_queue_t *queue, struct process_t *process) +{ + for(size_t i = 0; i < queue->size; i++) + { + if(queue->heap[i] == process) + { + queue->size--; + queue->heap[i] = queue->heap[queue->size]; + heapify(queue, i); + return S_OK; + } + } + return S_OUT_OF_BOUNDS; +} \ No newline at end of file diff --git a/src/quarkkernel.cpp b/src/quarkkernel.cpp deleted file mode 100755 index 069742f..0000000 --- a/src/quarkkernel.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -#include "systypes.hpp" -#include "systeminfo.hpp" -#include "mmgr.hpp" -#include "x86/pio.hpp" -#include "tty.hpp" -#include "util.hpp" -#include "config.h" - -using namespace kernel; - -extern SystemInfo system_info; -extern MemoryMap::Region memory_map; - -void main(char* cmdline) -{ - TTY tty((char*) 0xFF8B8000); - tty << PACKAGE_STRING << "\n\n"; - tty << "Low memory: \t" << (int) system_info.getLowMemory() << " KiB\n"; - tty << "High memory:\t" << (int) system_info.getHighMemory() << " KiB\n"; - tty << "Type\t\tLocation\t\tSize\n"; - MemoryMap memmap(&memory_map, 16); - for(size_t i = 0; i < memmap.size() && memmap[i].getSize() > 0; i++) - { - tty << (int) memmap[i].getType() << "\t\t\t"; - tty << (void*) memmap[i].getLocation() << "\t\t"; - tty << (int) memmap[i].getSize() << "\n"; - } - BuddyAllocator alloc(memmap, (char*) 0xFF800000, system_info.getHighMemory() / 4 + 256, 6); - mmap(alloc, (void*) 0, 4096, MMAP_RW); - outb(0xa1, 0xff); - outb(0x21, 0xff); - tty << "Nothing left to do. Hanging.\n"; -} diff --git a/src/scheduler.cpp b/src/scheduler.cpp deleted file mode 100644 index 718d8ca..0000000 --- a/src/scheduler.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "scheduler.hpp" - -kernel::ProcessQueue::ProcessQueue(Process** array) -{ - m_array = array; - m_size = 0; -} - -kernel::Process* kernel::ProcessQueue::extractMin() -{ - if(m_size == 0) - return NULL; - m_size--; - Process* p = m_array[0]; - m_array[0] = m_array[m_size]; - heapify(0); -} - -void kernel::ProcessQueue::insert(Process* n) -{ - size_t i = m_size; - m_size++; - for(; i > 0 && m_array[(i - 1) / 2]->priority > n->priority; i = (i - 1) / 2) - { - m_array[i] = m_array[(i - 1) / 2]; - } - m_array[i] = n; -} - -void kernel::ProcessQueue::remove(Process* n) -{ - for(size_t i = 0; i < m_size; i++) - { - if(m_array[i] == n) - { - m_size--; - m_array[i] = m_array[m_size]; - heapify(i); - break; - } - } -} - -void kernel::ProcessQueue::heapify(size_t i) -{ - if(i * 2 + 1 >= m_size) - return; - if (m_array[i]->priority >= m_array[i * 2 + 1]->priority && m_array[i * 2 + 1]->priority <= m_array[i * 2 + 2]->priority) - { - Process* buffer = m_array[i]; - m_array[i] = m_array[i * 2 + 1]; - m_array[i * 2 + 1] = buffer; - heapify(i * 2 + 1); - } - else if (m_array[i]->priority >= m_array[i * 2 + 2]->priority && m_array[i * 2 + 2]->priority <= m_array[i * 2 + 1]->priority) - { - Process* buffer = m_array[i]; - m_array[i] = m_array[i * 2 + 2]; - m_array[i * 2 + 2] = buffer; - heapify(i * 2 + 2); - } -} \ No newline at end of file diff --git a/src/scheduler.hpp b/src/scheduler.hpp deleted file mode 100644 index 982795e..0000000 --- a/src/scheduler.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef SCHEDULER_H -#define SCHEDULER_H - -#include - -namespace kernel -{ - -class Process -{ -public: - - Process(); - - size_t priority; - - void* stack; - -}; - -class ProcessQueue -{ -public: - - ProcessQueue(Process** array); - - Process* extractMin(); - - void insert(Process* n); - - void remove(Process* n); - -private: - - void heapify(size_t index); - - Process** m_array; - - size_t m_size; - -}; - -}; - -#endif \ No newline at end of file diff --git a/src/stdio.c b/src/stdio.c new file mode 100644 index 0000000..1e2165d --- /dev/null +++ b/src/stdio.c @@ -0,0 +1,100 @@ +#include "stdio.h" +#include +#include + +enum format_flags_t +{ + FORMAT_PADDING = '0', + FORMAT_WIDTH = '*', + + FORMAT_SIGNED_DECIMAL = 'i', + FORMAT_UNSIGNED_DECIMAL = 'u', + FORMAT_UNSIGNED_OCTAL = 'o', + FORMAT_UNSIGNED_HEX = 'x', + FORMAT_STRING = 's', + FORMAT_COUNT = 'n', + FORMAT_PERCENT = '%' + +}; + +char *itoa(unsigned int n, unsigned int base, unsigned int width) +{ + if (base < 2 || base > 16) + { + return NULL; + } + static const char *digits = "0123456789abcdef"; + static char buffer[65]; + char *s = &buffer[64]; + unsigned int count = 0; + do + { + *--s = digits[n % base]; + n /= base; + count++; + } while (count < width || n != 0); + return s; +} + +int printf(const char *format, ...) +{ + va_list valist; + va_start(valist, format); + while (*format) + { + if (*format == '%') + { + size_t width = 0; + bool padding = false; + switch (*++format) + { + case FORMAT_PADDING: + padding = true; + format++; + break; + } + while (*format >= '0' && *format <= '9') + { + width = (width * 10) + *format - '0'; + format++; + } + switch (*format) + { + case FORMAT_SIGNED_DECIMAL:; + int n = va_arg(valist, int); + if (n < 0) + { + putchar('-'); + n *= -1; + } + puts(itoa((unsigned int)n, 10, width)); + break; + case FORMAT_UNSIGNED_DECIMAL: + puts(itoa(va_arg(valist, unsigned int), 10, width)); + break; + case FORMAT_UNSIGNED_OCTAL: + puts(itoa(va_arg(valist, unsigned int), 8, width)); + case FORMAT_UNSIGNED_HEX: + puts(itoa(va_arg(valist, unsigned int), 16, width)); + break; + case FORMAT_STRING: + puts(va_arg(valist, const char *)); + break; + case FORMAT_PERCENT: + putchar('%'); + break; + } + } + else + { + putchar(*format); + } + format++; + } + va_end(valist); + return 0; +} + +int sprintf(char *str, const char *format, ...) +{ +} \ No newline at end of file diff --git a/src/string.c b/src/string.c new file mode 100644 index 0000000..4dd71ab --- /dev/null +++ b/src/string.c @@ -0,0 +1,110 @@ +#include "string.h" +#include +#include + +void *memcpy(void *destination, const void *source, size_t num) +{ + if (num > 0) + { + const uint8_t *src = (const uint8_t *)source; + uint8_t *dest = (uint8_t *)destination; + for (size_t i = 0; i < num; i++) + { + dest[i] = src[i]; + } + } + return destination; +} + +void *memmove(void *destination, const void *source, size_t num) +{ + if (num > 0) + { + if (((size_t)destination) < ((size_t)source) || ((size_t)destination) >= (((size_t)source)) + num) + { + return memcpy(destination, source, num); + } + else if (destination != source) + { + size_t i = num - 1; + const uint8_t *src = (const uint8_t *)source; + uint8_t *dest = (uint8_t *)destination; + do + { + dest[i] = src[i]; + i--; + } while (i != 0); + } + } + return destination; +} + +int memcmp(const void *ptr1, const void *ptr2, size_t num) +{ + const uint8_t *a = (const uint8_t *)ptr1; + const uint8_t *b = (const uint8_t *)ptr2; + for (size_t i = 0; i < num; i++) + { + if (a[i] < b[i]) + return -1; + else if (a[i] > b[i]) + return 1; + } + return 0; +} + +void *memset(void *ptr, int value, size_t num) +{ + uint8_t *dest = (uint8_t *)ptr; + uint8_t v = (uint8_t)value; + for (size_t i = 0; i < num; i++) + { + dest[i] = v; + } + return ptr; +} + +int strlen(const char *str) +{ + int i = 0; + while (str[i] != '\0') + { + i++; + } + return i; +} + +char *strcpy(char *destination, const char *source) +{ + int sourceLen = strlen(source); + if ((destination <= source) || (destination > (source + sourceLen))) + { + char *d = destination; + const char *s = source; + while (true) + { + *d = *s; + if (*s == '\0') + { + break; + } + else + { + s++; + d++; + } + } + } + else + { + char *d = destination + sourceLen; + const char *s = source + sourceLen; + do + { + *d = *s; + d--; + s--; + } while (d > destination); + } + return destination; +} diff --git a/src/systeminfo.cpp b/src/systeminfo.cpp deleted file mode 100644 index 0ed92e4..0000000 --- a/src/systeminfo.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "systeminfo.hpp" - -size_t kernel::SystemInfo::getLowMemory() -{ - return lowMemory; -} - -size_t kernel::SystemInfo::getHighMemory() -{ - return highMemory; -} - -physaddr_t kernel::SystemInfo::getKernelBase() -{ - return kernelBase; -} diff --git a/src/systeminfo.hpp b/src/systeminfo.hpp deleted file mode 100644 index 33ef728..0000000 --- a/src/systeminfo.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef SYSTEMINFO_H -#define SYSTEMINFO_H - -#include - -#include "systypes.hpp" - -namespace kernel -{ - -class SystemInfo -{ -public: - - size_t getLowMemory(); - - size_t getHighMemory(); - - physaddr_t getKernelBase(); - -private: - - size_t lowMemory; - - size_t highMemory; - - physaddr_t kernelBase; - -}; - -} - -#endif diff --git a/src/tty.cpp b/src/tty.cpp deleted file mode 100644 index b3132c5..0000000 --- a/src/tty.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include -#include "tty.hpp" - -kernel::TTY::TTY(char* vga) -{ - this->vga = vga; - this->cursor = 0; - this->width = 0; - this->base = 10; -} - -kernel::TTY& kernel::TTY::operator<<(kernel::TTY::Format fmt) -{ - switch(fmt) - { - case Binary: - base = 2; - break; - case Decimal: - base = 10; - break; - case Hex: - base = 16; - break; - } -} - -kernel::TTY& kernel::TTY::operator<<(const char* str) -{ - return printString(str); -} - -kernel::TTY& kernel::TTY::operator<<(unsigned int n) -{ - return printNumber(n, base, width); -} - -kernel::TTY& kernel::TTY::operator<<(int n) -{ - return printNumber((unsigned int) n, base, width); -} - -kernel::TTY& kernel::TTY::operator<<(void* n) -{ - return printNumber((unsigned int) n, 16, 8); -} - -kernel::TTY& kernel::TTY::operator<<(char c) -{ - return putChar(c); -} - -void kernel::TTY::setWidth(size_t width) -{ - this->width = width; -} - -size_t kernel::TTY::getWidth() -{ - return width; -} - -void kernel::TTY::clear() -{ - for(int i = 0; i < 80*25; i++) - { - vga[i * 2] = ' '; - } - cursor = 0; -} - -kernel::TTY& kernel::TTY::printNumber(unsigned int n, size_t base, - size_t width) -{ - const char* digits = "0123456789ABCDEF"; - char str[33]; - size_t i = 1; - do - { - str[i] = digits[n % base]; - n /= base; - i++; - } while(n > 0); - while(i <= width) - { - str[i] = '0'; - i++; - } - str[0] = '\0'; - for(char* s = str + (i - 1); *s; s--) - { - putChar(*s); - } - return *this; -} - -kernel::TTY& kernel::TTY::printString(const char* str) -{ - while(*str) - { - putChar(*str); - str++; - } - return *this; -} - -kernel::TTY& kernel::TTY::putChar(char c) -{ - switch(c) - { - case '\n': - cursor = (cursor + 80) - (cursor % 80); - break; - case '\t': - cursor = (cursor + 4) - (cursor % 4); - break; - case '\r': - cursor -= cursor % 160; - break; - default: - vga[cursor * 2] = c; - cursor++; - } - return *this; -} diff --git a/src/tty.hpp b/src/tty.hpp deleted file mode 100644 index 47b5191..0000000 --- a/src/tty.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef TTY_H_ -#define TTY_H_ - -#include - -namespace kernel -{ - -class TTY -{ -public: - - enum Format - { - Binary, - Decimal, - Hex - }; - - TTY(char* vga); - - TTY& operator<<(Format fmt); - - TTY& operator<<(const char* str); - - TTY& operator<<(unsigned int n); - - TTY& operator<<(int n); - - TTY& operator<<(void* n); - - TTY& operator<<(char c); - - void setWidth(size_t width); - - size_t getWidth(); - - void clear(); - -private: - - TTY& printNumber(unsigned int n, size_t base, size_t width); - - TTY& printString(const char* str); - - TTY& putChar(char c); - - char* vga; - - int cursor; - - size_t width; - - size_t base; - -}; - -} - -#endif diff --git a/src/util.cpp b/src/util.cpp deleted file mode 100644 index fe13afc..0000000 --- a/src/util.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include - -#include "util.hpp" - -void* memcpy(void* destination, const void* source, size_t num) -{ - if(num > 0) - { - const uint8_t* src = (const uint8_t*) source; - uint8_t* dest = (uint8_t*) destination; - for(size_t i = 0; i < num; i++) - { - dest[i] = src[i]; - } - } - return destination; -} - -/* - * There are four distinct cases here: - * 1. destination and source blocks do not overlap - * 2. destination and source are the same - * 3. destination and source do overlap; destination starts before source - * 4. destination and source do overlap; destination starts after source - * - * Memcpy results in expected behavior in all cases except for case 4. In that - * case, copying must be done backwards to avoid reading from bytes that have - * already been overwritten. - */ -void* memmove(void* destination, const void* source, size_t num) -{ - if(num > 0) - { - if(((size_t) destination) < ((size_t) source) || ((size_t) destination) >= (((size_t) source)) + num) - { - return memcpy(destination, source, num); - } - else if(destination != source) - { - size_t i = num - 1; - const uint8_t* src = (const uint8_t*) source; - uint8_t* dest = (uint8_t*) destination; - do - { - dest[i] = src[i]; - i--; - } while(i != 0); - } - } - return destination; -} - -int memcmp(const void* ptr1, const void* ptr2, size_t num) -{ - const uint8_t* a = (const uint8_t*) ptr1; - const uint8_t* b = (const uint8_t*) ptr2; - for(size_t i = 0; i < num; i++) - { - if(a[i] < b[i]) - return -1; - else if(a[i] > b[i]) - return 1; - } - return 0; -} - -void* memset (void* ptr, int value, size_t num) -{ - uint8_t* dest = (uint8_t*) ptr; - uint8_t v = (uint8_t) value; - for(size_t i = 0; i < num; i++) - { - dest[i] = v; - } - return ptr; -} - -void __cxa_pure_virtual() -{ - // do nothing -} \ No newline at end of file diff --git a/src/util.hpp b/src/util.hpp deleted file mode 100644 index acf21d0..0000000 --- a/src/util.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef UTIL_H -#define UTIL_H - -#include - -extern "C" void __cxa_pure_virtual(); - -extern "C" void* memcpy(void* destination, const void* source, size_t num); - -extern "C" void* memmove(void* destination, const void* source, size_t num); - -extern "C" int memcmp(const void* ptr1, const void* ptr2, size_t num); - -extern "C" void* memset(void* ptr, int value, size_t num); - -#endif \ No newline at end of file diff --git a/src/x86/apic.c b/src/x86/apic.c new file mode 100644 index 0000000..9d6d113 --- /dev/null +++ b/src/x86/apic.c @@ -0,0 +1,35 @@ +#include "apic.h" + +void apic_enable() +{ + +} + +void apic_eoi() +{ + apic_registers->eoi.value = 0; +} + +void apic_send_ipi( + uint32_t vector, + enum apic_delivery_mode_t delivery_mode, + enum apic_destination_mode_t destination_mode, + enum apic_level_t level, + enum apic_trigger_mode_t trigger_mode, + enum apic_destination_shorthand_t shorthand, + uint32_t destination) +{ + struct apic_icr_t value = { + .vector = vector, + .delivery_mode = delivery_mode, + .destination_mode = destination_mode, + .level = level, + .trigger_mode = trigger_mode, + .destination_shorthand = shorthand, + .destination = destination + }; + uint32_t *value_addr = (uint32_t*) &value; + uint32_t *icr_addr = (uint32_t*)&apic_registers->interrput_command; + icr_addr[4] = value_addr[4]; + icr_addr[0] = value_addr[0]; +} \ No newline at end of file diff --git a/src/x86/apic.h b/src/x86/apic.h new file mode 100644 index 0000000..65e7739 --- /dev/null +++ b/src/x86/apic.h @@ -0,0 +1,156 @@ +#pragma once + +#include + +enum apic_delivery_mode_t +{ + APIC_DELIVERY_MODE_FIXED = 0b000, + APIC_DELIVERY_MODE_LOWEST_PRIORITY = 0b001, + APIC_DELIVERY_MODE_SMI = 0b010, + APIC_DELIVERY_MODE_NMI = 0b100, + APIC_DELIVERY_MODE_INIT = 0b101, + APIC_DELIVERY_MODE_SIPI = 0b110, + APIV_DELIVERY_MODE_EXTINIT = 0b111 +}; + +enum apic_destination_mode_t +{ + APIC_DESTINATION_MODE_PHYSICAL = 0, + APIC_DESTINATION_MODE_LOGICAL = 1 +}; + +enum apic_level_t +{ + APIC_LEVEL_DEASSERT = 0, + APIC_LEVEL_ASSERT = 1 +}; +enum apic_trigger_mode_t +{ + APIC_TRIGGER_MODE_EDGE = 0, + APIC_TRIGGER_MODE_LEVEL = 1 +}; + +enum apic_destination_shorthand_t +{ + APIC_DEST_SHORTHAND_NONE = 0, + APIC_DEST_SHORTHAND_SELF = 1, + APIC_DEST_SHORTHAND_ALL = 2, + APIC_DEST_SHORTHAND_OTHERS = 3 +}; + +enum apic_divide_mode_t +{ + APIC_DIVIDE_1 = 0b1011, + APIC_DIVIDE_2 = 0b0000, + APIC_DIVIDE_4 = 0b0001, + APIC_DIVIDE_8 = 0b0010, + APIC_DIVIDE_16 = 0b0011, + APIC_DIVIDE_32 = 0b1000, + APIC_DIVIDE_64 = 0b1001, + APIC_DIVIDE_128 = 0b1011 +}; + +enum apic_timer_mode_t +{ + APIC_TIMER_ONESHOT = 0, + APIC_TIMER_PERIODIC = 1, + APIC_TIMER_TSCDEADLINE = 2 +}; + +struct apic_register_t +{ + uint32_t value; + uint32_t padding[3]; +}; + +struct apic_lapic_version_t +{ + uint32_t version : 8; + uint32_t reserved_1 : 8; + uint32_t max_lvt_entry : 8; + uint32_t suppress_eoi_broadcast : 1; + uint32_t reserved_2 : 7; + uint32_t padding[3]; +}; + +struct apic_lvt_t +{ + uint32_t vector: 8; + uint32_t delivery_mode : 3; + uint32_t reserved_1 : 1; + uint32_t delivery_status : 1; + uint32_t pin_polarity : 1; + uint32_t remote_irr : 1; + uint32_t trigger_mode : 1; + uint32_t mask : 1; + uint32_t timer_mode : 2; + uint32_t reserved_2 : 13; + uint32_t padding[3]; +}; + +struct apic_icr_t +{ + uint32_t vector : 8; + uint32_t delivery_mode : 3; + uint32_t destination_mode : 1; + uint32_t delivery_status : 1; + uint32_t reserved_1 : 1; + uint32_t level : 1; + uint32_t trigger_mode : 1; + uint32_t reserved_2 : 2; + uint32_t destination_shorthand : 2; + uint32_t reserved_3 : 12; + uint32_t padding_1[3]; + uint32_t reserved : 24; + uint32_t destination : 8; + uint32_t padding_2[3]; +}; + +struct apic_registers_t +{ + struct apic_register_t reserved_1[2]; + struct apic_register_t lapic_id; + struct apic_lapic_version_t lapic_version; + struct apic_register_t reserved_2[4]; + struct apic_register_t task_priority; + struct apic_register_t arbitration_priority; + struct apic_register_t processor_priority; + struct apic_register_t eoi; + struct apic_register_t remote_read; + struct apic_register_t logical_destination; + struct apic_register_t destination_format; + struct apic_register_t spurious_iv; + struct apic_register_t in_service[8]; + struct apic_register_t trigger_mode[8]; + struct apic_register_t interrupt_request[8]; + struct apic_register_t error_status; + struct apic_register_t reserved_3[6]; + struct apic_lvt_t lvt_cmci; + struct apic_icr_t interrput_command; + struct apic_lvt_t lvt_timer; + struct apic_lvt_t lvt_thermal_sensor; + struct apic_lvt_t lvt_performance_counters; + struct apic_lvt_t lvt_lint0; + struct apic_lvt_t lvt_lint1; + struct apic_lvt_t lvt_error; + struct apic_register_t initial_count; + struct apic_register_t current_count; + struct apic_register_t reserved_4[4]; + struct apic_register_t divide_config; + struct apic_register_t reserved_5; +}; + +extern struct apic_registers_t volatile *apic_registers; + +void apic_enable(); + +void apic_eoi(); + +void apic_send_ipi( + uint32_t vector, + enum apic_delivery_mode_t delivery_mode, + enum apic_destination_mode_t destination_mode, + enum apic_level_t level, + enum apic_trigger_mode_t trigger_mode, + enum apic_destination_shorthand_t shorthand, + uint32_t destination); diff --git a/src/x86/entry.S b/src/x86/entry.S index 55dc9d0..6ec1c8b 100755 --- a/src/x86/entry.S +++ b/src/x86/entry.S @@ -1,5 +1,98 @@ .section .multiboot -.include "x86/multiboot2header.S" + +/* + * Define constants for the multiboot header. See Multiboot 2 Specifications for details. + */ +.set align, 1<<0 +.set meminfo, 1<<1 +.set magic, 0xE85250D6 +.set arch, 0 +.set headerLength, _multibootHeaderEnd - _multibootHeaderStart +.set checksum, -(magic + arch + headerLength) + +.set tagNotOptional, 0 + +.set tagInfoRequestType, 1 +.set tagInfoRequestSize, _multibootInfoTagEnd - _multibootInfoTagStart +.set requestBootCommand, 1 +.set requestBootLoaderName, 2 +.set requestBootModules, 3 +.set requestMemoryInfo, 4 +.set requestBootDevice, 5 +.set requestMemoryMap, 6 + +.set tagAddressType, 2 +.set tagAddressSize, 24 +.set tagAddressHeaderLocation, LOAD_START +.set tagAddressLoadStart, LOAD_START +.set tagAddressLoadEnd, LOAD_END +.set tagAddressBSSEnd, BSS_END + +.set tagEntryType, 3 +.set tagEntrySize, 12 +.set tagEntryAddress, _start - (0xFF900000 - 0x100000) + +.set tagModuleAlignType, 6 +.set tagModuleAlignSize, 8 + +/* + * Each multiboot tag must be 8-byte aligned, or GRUB will not be able to read the header. + */ +.align 8 +_multibootHeaderStart: + +.long magic +.long arch +.long headerLength +.long checksum + +.align 8 + +_multibootInfoTagStart: +.short tagInfoRequestType +.short tagNotOptional +.long tagInfoRequestSize +.long requestBootCommand +.long requestBootLoaderName +.long requestBootModules +.long requestMemoryInfo +.long requestBootDevice +.long requestMemoryMap +_multibootInfoTagEnd: + +.align 8 + +.short tagAddressType +.short tagNotOptional +.long tagAddressSize +.long tagAddressHeaderLocation +.long tagAddressLoadStart +.long tagAddressLoadEnd +.long tagAddressBSSEnd + +.align 8 + +.short tagEntryType +.short tagNotOptional +.long tagEntrySize +.long tagEntryAddress + +.align 8 + +.short tagModuleAlignType +.short tagNotOptional +.long tagModuleAlignSize + +.align 8 + +/* + * Terminate list of multiboot header tags. + * Ending tag has type = 0, flags = 0, size = 8 + */ +.long 0 +.long 8 + +_multibootHeaderEnd: .section .rodata @@ -31,7 +124,7 @@ _tempPgDir: _tempIdentityMap: .skip 4096 _tempPgTable: -.skip 8192 +.skip 4096 _bootCmdLine: .skip 64 @@ -50,181 +143,57 @@ memory_map: .global _start .type _start, @function _start: + + cli + + # This platform reqires a Multiboot2 bootloader. cmp $0x36d76289, %eax - jne _err + jne .err - movb $64, 0xB8000 + # Initialize stack in physical address space + mov $stackTop, %esp + sub $BASE_DIFF, %esp - 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 $3, %eax - je tag_3 - 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 - -tag_3: - mov 8(%ebx), %esi - mov (%esi), %eax - mov %al, (0xB8004) - mov %ah, (0xB8006) - shr $16, %eax - mov %al, (0xB8008) - mov %ah, (0xB800a) - 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 - or $3, %eax - - # Load the address of the temporary page table and translate it to a physical address - mov $_tempPgTable, %edi - sub $BASE_DIFF, %edi - - # Save the PTE into an entry in the temporary page table - mov %eax, (%edi, %ecx, 4) - - # Load the address of the identity map and translate it to a physical address - mov $_tempIdentityMap, %edi - sub $BASE_DIFF, %edi - - # Save the PTE into an entry in the identity map - mov %eax, (%edi, %ecx, 4) - - # Increment count and loop - inc %ecx - mov $IMAGE_SIZE, %edx - add $256, %edx - cmp %edx, %ecx - jne 1b - - # Load the physical address of the identity map, and generate a PDE + # Push physical address of identity map mov $_tempIdentityMap, %eax sub $BASE_DIFF, %eax - or $3, %eax + push %eax - # Load the physical address of the page directory - mov $_tempPgDir, %edi - sub $BASE_DIFF, %edi - - # Save the PDE to the first element in the page directory - mov %eax, (%edi) - - # Load the physical address of the temporary page table, and generate a PDE + # Push physical address of page table mov $_tempPgTable, %eax sub $BASE_DIFF, %eax - or $3, %eax + push %eax - # Save the PDE to the entry corresponding to 0xC0000000 - mov %eax, 4088(%edi) - - # Set the last entry in the page directory to point to the page directory itself - mov %edi, %eax - or $3, %eax - mov %eax, 4092(%edi) + # Push physical address of page directory + mov $_tempPgDir, %eax + sub $BASE_DIFF, %eax + push %eax - # Load the physical address of the page directory into CR3 - mov $_tempPgDir, %edi - sub $BASE_DIFF, %edi - mov %edi, %cr3 - - # Enable paging - mov %cr0, %eax - or $0x80010000, %eax - mov %eax, %cr0 + # Load physical address of startPaging() + mov $startPaging, %eax + sub $BASE_DIFF, %eax + + # Initialize paging + call *%eax # Jump into mapped kernel binary - lea 2f, %eax + lea 1f, %eax jmp *%eax -2: +1: # Delete PDE corresponding to identity map. We shouldn't need it anymore. movl $0, (_tempIdentityMap) - # Reload page tables + # Flush TLB mov %cr3, %eax mov %eax, %cr3 - # Initialize stack + # Initialize stack in virtual memory mov $stackTop, %esp + + # Load GPT lgdt gdt_info + # Load segment registers jmp $8, $.ldcs .ldcs: mov $16, %ax @@ -234,15 +203,21 @@ s_end: mov %ax, %fs mov %ax, %ss - mov $_bootCmdLine, %eax - push %eax - - # Call main function - call main + # Change EBX to point to the virtual address of the multiboot info + # If the new pointer is out-of-bounds, error + add $0xFF800000, %ebx + cmp $0xFF800000, %ebx + jl .err + cmp $0xFFC00000, %ebx + jge .err -_err: + # Call initialize(void* multibootInfo) + push %ebx + call initialize + +.err: cli -3: hlt - jmp 3b +2: hlt + jmp 2b .size _start, . - _start diff --git a/src/x86/idt.S b/src/x86/idt.S deleted file mode 100644 index a76f770..0000000 --- a/src/x86/idt.S +++ /dev/null @@ -1,21 +0,0 @@ -.section .bss - -.align 8 -.global idt -idt: -.skip 8 * 256 -idt_end: - -.section .rodata - -.idt_info: -.short idt_end - idt - 1 -.long idt - -.section .text - -.global _lidt -.type _lidt, @function -_lidt: - - ret \ No newline at end of file diff --git a/src/x86/idt.hpp b/src/x86/idt.hpp deleted file mode 100644 index 2c1cf0f..0000000 --- a/src/x86/idt.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef IDT_H -#define IDT_H - -#include "interruptdescriptor.hpp" - -extern kernel::InterruptDescriptor idt[256]; - -extern "C" void _lidt(); - -#endif \ No newline at end of file diff --git a/src/x86/interruptdescriptor.cpp b/src/x86/interruptdescriptor.cpp deleted file mode 100644 index 63803e6..0000000 --- a/src/x86/interruptdescriptor.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "interruptdescriptor.hpp" - -kernel::InterruptDescriptor::InterruptDescriptor() -{ - this->m_offset1 = 0; - this->m_selector = 0; - this->m_zero = 0; - this->m_type = 0; - this->m_storage = 0; - this->m_dpl = 0; - this->m_present = 0; - this->m_offset2 = 0; -} - -kernel::InterruptDescriptor::InterruptDescriptor(void* handler, Type type, unsigned int dpl) -{ - uint32_t offset = (uint32_t) handler; - this->m_offset1 = (uint16_t) offset; - this->m_selector = 8; - this->m_zero = 0; - this->m_type = (uint16_t) type; - this->m_storage = 0; - this->m_dpl = dpl; - this->m_present = 1; - this->m_offset2 = offset >> 16; -} - -bool kernel::InterruptDescriptor::present() -{ - return m_present == 1; -} -void kernel::InterruptDescriptor::present(bool present) -{ - m_present = present ? 1 : 0; -} - -kernel::InterruptDescriptor::Type kernel::InterruptDescriptor::type() -{ - return (Type) m_type; -} - -void kernel::InterruptDescriptor::type(kernel::InterruptDescriptor::Type type) -{ - m_type = (unsigned int) type; -} - -unsigned int kernel::InterruptDescriptor::dpl() -{ - return m_dpl; -} - -void kernel::InterruptDescriptor::dpl(unsigned int dpl) -{ - m_dpl = dpl; -} - -void* kernel::InterruptDescriptor::operator=(void* rhs) -{ - uint32_t offset = (uint32_t) rhs; - m_offset1 = (uint16_t) offset; - m_offset2 = (offset >> 16); - return rhs; -} diff --git a/src/x86/interruptdescriptor.hpp b/src/x86/interruptdescriptor.hpp deleted file mode 100644 index c4365fe..0000000 --- a/src/x86/interruptdescriptor.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef INTERRUPTDESCRIPTOR_H -#define INTERRUPTDESCRIPTOR_H - -#include - -namespace kernel -{ - -class InterruptDescriptor -{ -public: - - enum Type - { - TASK32 = 5, - TRAP32 = 15, - INT32 = 14, - TRAP16 = 7, - INT16 = 6 - }; - - InterruptDescriptor(); - - InterruptDescriptor(void* handler, Type type, unsigned int dpl); - - bool present(); - - void present(bool present); - - Type type(); - - void type(Type type); - - unsigned int dpl(); - - void dpl(unsigned int dpl); - - void* operator=(void* rhs); - -private: - - uint16_t m_offset1; - uint16_t m_selector; - uint16_t m_zero : 8; - uint16_t m_type : 4; - uint16_t m_storage : 1; - uint16_t m_dpl : 2; - uint16_t m_present : 1; - uint16_t m_offset2; - -}; - -} - -#endif diff --git a/src/x86/interrupts.c b/src/x86/interrupts.c new file mode 100644 index 0000000..aadce4a --- /dev/null +++ b/src/x86/interrupts.c @@ -0,0 +1,29 @@ +#include "interrupts.h" + +struct idt_info_t +{ + uint16_t size; + void *location; +} __attribute__ ((packed)); + +void lidt(struct interrupt_descriptor_t *idt) +{ + struct idt_info_t idt_info; + idt_info.size = sizeof(struct interrupt_descriptor_t) * 256 - 1; + idt_info.location = (void *)idt; + asm("lidt (%0)" + : + : "r"(&idt_info)); +} + +void create_interrupt_descriptor(struct interrupt_descriptor_t *descriptor, void *isr, enum isr_type_t type, uint32_t privilage) +{ + descriptor->offset_1 = (uint32_t) isr & 0xFFFF; + descriptor->offset_2 = (uint32_t) isr >> 16; + descriptor->selector = 8; + descriptor->zero = 0; + descriptor->type = type; + descriptor->storage = 0; + descriptor->dpl = privilage; + descriptor->present = 1; +} diff --git a/src/x86/interrupts.cpp b/src/x86/interrupts.cpp deleted file mode 100644 index 9e5c964..0000000 --- a/src/x86/interrupts.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "../interrupts.hpp" -#include "idt.hpp" -#include "inthandlers.hpp" - -kernel::Interrupts::Interrupts() -{ - idt[0] = InterruptDescriptor((void*) &divisionByZero, InterruptDescriptor::INT32, 0); - idt[8] = InterruptDescriptor((void*) &doubleFaultHandler, InterruptDescriptor::INT32, 0); - idt[0x80] = InterruptDescriptor((void*) &syscallHandler, InterruptDescriptor::INT32, 0); - // Load interrupt handlers - // Configure PIC - _lidt(); -} - -inline void kernel::Interrupts::enable() -{ - asm("sti"); -} - -inline void kernel::Interrupts::disable() -{ - asm("cli"); -} \ No newline at end of file diff --git a/src/x86/interrupts.h b/src/x86/interrupts.h new file mode 100644 index 0000000..d8ff3b9 --- /dev/null +++ b/src/x86/interrupts.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +enum interrupt_code_t +{ + EXCEPTION_DIV_BY_0 = 0, + EXCEPTION_DEBUG = 1, + EXCEPTION_NMI = 2, + EXCEPTION_BREAKPOINT = 3, + EXCEPTION_OVERFLOW = 4, + EXCEPTION_OUT_OF_BOUNDS = 5, + EXCEPTION_INVALID_OPCODE = 6, + EXCEPTION_DEVICE_NOT_AVAILABLE = 7, + EXCEPTION_DOUBLE_FAULT = 8, + EXCEPTION_INVALID_TSS = 10, + EXCEPTION_SEGMENT_NOT_PRESENT = 11, + EXCEPTION_STACK_SEGMENT_FAULT = 12, + EXCEPTION_GPF = 13, + EXCEPTION_PAGE_FAULT = 14, + EXCEPTION_x87_FLOATING_POINT = 16, + EXCEPTION_ALIGNMENT_CHECK = 17, + EXCEPTION_MACHINE_CHECK = 18, + EXCEPTION_SIMD_FLOATING_POINT = 19, + EXCEPTION_VIRTUALIZATION = 20, + EXCEPTION_SECURITY = 30, + ISR_AP_START = 127, + ISR_SYSCALL = 128 +}; + +enum isr_type_t +{ + INTERRPUT_TASK32 = 5, + INTERRPUT_TRAP32 = 15, + INTERRPUT_INT32 = 14, + INTERRPUT_TRAP16 = 7, + INTERRPUT_INT16 = 6 +}; + +struct interrupt_descriptor_t +{ + uint16_t offset_1; + uint16_t selector; + uint16_t zero : 8; + uint16_t type : 4; + uint16_t storage : 1; + uint16_t dpl : 2; + uint16_t present : 1; + uint16_t offset_2; +}; + +void lidt(struct interrupt_descriptor_t *idt); + +void create_interrupt_descriptor(struct interrupt_descriptor_t *descriptor, void *isr, enum isr_type_t type, uint32_t privilage); diff --git a/src/x86/inthandlers.cpp b/src/x86/inthandlers.cpp deleted file mode 100644 index 6519620..0000000 --- a/src/x86/inthandlers.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "inthandlers.hpp" - -char* display = (char*) 0xC00B8000; - -__attribute__ ((interrupt)) -void divisionByZero(void* frame) -{ - *display = 'z'; - display += 2; -} - -__attribute__ ((interrupt)) -void gpFaultHandler(void* frame, unsigned int error) -{ - *display = 'a'; - display += 2; -} - -__attribute__ ((interrupt)) -void pageFaultHandler(void* frame, unsigned int error) -{ - *display = '0'; - display += 2; -} - -__attribute__ ((interrupt)) -void doubleFaultHandler(void* frame, unsigned int error) -{ - *display = '#'; - asm("hlt"); -} - -__attribute__ ((interrupt)) -void syscallHandler(void* frame) -{ - *display = 'z'; - display += 2; -} - diff --git a/src/x86/inthandlers.hpp b/src/x86/inthandlers.hpp deleted file mode 100644 index bf92c56..0000000 --- a/src/x86/inthandlers.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef INTHANDLERS_H -#define INTHANDLERS_H - -__attribute__ ((interrupt)) -void divisionByZero(void* frame); - -__attribute__ ((interrupt)) -void gpFaultHandler(void* frame, unsigned int error); - -__attribute__ ((interrupt)) -void pageFaultHandler(void* frame, unsigned int error); - -__attribute__ ((interrupt)) -void doubleFaultHandler(void* frame, unsigned int error); - -__attribute__ ((interrupt)) -void syscallHandler(void* frame); - -#endif diff --git a/src/x86/isr.c b/src/x86/isr.c new file mode 100644 index 0000000..8d36841 --- /dev/null +++ b/src/x86/isr.c @@ -0,0 +1,41 @@ +#include "isr.h" +#include "stdio.h" + +__attribute__ ((interrupt)) +void isr_division_by_zero(void* frame) +{ + printf("Exception: Division by zero\n"); +} + +__attribute__ ((interrupt)) +void isr_gp_fault(void* frame, unsigned int error) +{ + +} + +__attribute__ ((interrupt)) +void isr_page_fault(void* frame, unsigned int error) +{ + +} + +__attribute__ ((interrupt)) +void isr_double_fault(void* frame, unsigned int error) +{ + asm("hlt"); +} + +__attribute__ ((naked)) +void isr_ap_start(void* frame) +{ + asm(".code16"); + //... + asm(".code32"); + // do something useful +} + +__attribute__ ((interrupt)) +void isr_syscall(void* frame) +{ + +} \ No newline at end of file diff --git a/src/x86/isr.h b/src/x86/isr.h new file mode 100644 index 0000000..1725d53 --- /dev/null +++ b/src/x86/isr.h @@ -0,0 +1,19 @@ +#pragma once + +__attribute__ ((interrupt)) +void isr_division_by_zero(void* frame); + +__attribute__ ((interrupt)) +void isr_gp_fault(void* frame, unsigned int error); + +__attribute__ ((interrupt)) +void isr_page_fault(void* frame, unsigned int error); + +__attribute__ ((interrupt)) +void isr_double_fault(void* frame, unsigned int error); + +__attribute__ ((naked)) +void isr_ap_start(void* frame); + +__attribute__ ((interrupt)) +void isr_syscall(void* frame); \ No newline at end of file diff --git a/src/x86/linker.ld b/src/x86/linker.ld index cfe1db2..bf01f37 100755 --- a/src/x86/linker.ld +++ b/src/x86/linker.ld @@ -1,5 +1,5 @@ ENTRY(_start) - + SECTIONS { . = 0xFF900000; @@ -33,4 +33,10 @@ SECTIONS 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; + + _pageMapLocation = 0xFF800000; + _heapLocation = 0xFFB00000; + _heapSize = 0x100000; + _kernelStart = VIRTUAL_BASE; + _kernel_end = VIRTUAL_BASE + (4096 * IMAGE_SIZE); } diff --git a/src/x86/mmap.cpp b/src/x86/mmap.cpp deleted file mode 100644 index 9bb61a1..0000000 --- a/src/x86/mmap.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "../mmap.hpp" -#include "pagetableentry.hpp" - -int kernel::mmap(MemoryAllocator& allocator, void* start, size_t length, int flags) -{ - if((size_t) start % 4096 != 0) - return -1; - PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000; - PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000; - 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 = allocator.allocate(4096); - if(newPT == 0) - return -1; - pageDirectory[directoryIndex] = newPT; - pageDirectory[directoryIndex].setPresent(true); - pageDirectory[directoryIndex].setUsermode(false); - pageDirectory[directoryIndex].setRw(true); - } - if(!pageTables[tableIndex].getPresent()) - { - physaddr_t page = allocator.allocate(4096); - pageTables[tableIndex] = page; - pageTables[tableIndex].setPresent(true); - pageTables[tableIndex].setUsermode(false); - if(flags & MMAP_RW) - pageTables[tableIndex].setRw(true); - - } - tableIndex++; - } - return 0; -} - -int kernel::munmap(MemoryAllocator& allocator, void* start, size_t length) -{ - if((size_t) start % 4096 != 0) - return -1; - PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000; - PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000; - 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()) - { - pageTables[tableIndex] = 0; - pageTables[tableIndex].setPresent(false); - pageTables[tableIndex].setUsermode(false); - pageTables[tableIndex].setRw(false); - } - tableIndex++; - } - return 0; -} - -bool kernel::isMapped(void* addr) -{ - PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000; - size_t tableIndex = (size_t) addr / 4096; - size_t directoryIndex = tableIndex / 1024; - if(pageDirectory[directoryIndex].getPresent()) - { - PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000; - return pageTables[tableIndex].getPresent(); - } - return false; -} - -physaddr_t kernel::getPhysicalAddress(void* addr) -{ - PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000; - size_t tableIndex = (size_t) addr / 4096; - return pageTables[tableIndex].getPhysicalAddress() + ((size_t) addr & 0xFFF); -} - -int kernel::createAddressSpace(void* table) -{ - if(((size_t) table & 0xFFF) != 0) - return -1; - PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000; - PageTableEntry* newDirectory = (PageTableEntry*) table; - newDirectory[1022] = pageDirectory[1022]; - newDirectory[1023] = pageDirectory[1023]; - return 0; -} - -int kernel::loadAddressSpace(physaddr_t table) -{ - if((table & 0xFFF) != 0) - return -1; - asm("mov %0, %%cr3" - : - : "r" (table)); - return 0; -} \ No newline at end of file diff --git a/src/x86/mmgr.c b/src/x86/mmgr.c new file mode 100644 index 0000000..a12be9f --- /dev/null +++ b/src/x86/mmgr.c @@ -0,0 +1,123 @@ +#include "mmgr.h" +#include "pageallocator.h" +#include "string.h" +#include "types/status.h" +#include + +const size_t page_size = 4096; + +const size_t page_bits = 12; + +struct page_table_entry_t +{ + 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; +}; + +struct page_table_entry_t *page_tables = (struct page_table_entry_t *)0xFFC00000; + +struct page_table_entry_t *page_directory = (struct page_table_entry_t *)0xFFFFF000; + +physaddr_t create_address_space(struct page_stack_t *page_stack) +{ + physaddr_t table = reserve_page(page_stack); + if (table == S_OUT_OF_MEMORY) + { + return S_OUT_OF_MEMORY; + } + struct page_table_entry_t buffer = page_directory[0]; + page_directory[0].physicalAddress = table >> page_bits; + asm volatile("invlpg 0xFFC00000" :: + : "memory"); + memset((void *)page_tables, 0, 1022 * 4); + page_tables[1022] = page_directory[1022]; + page_tables[1023] = page_directory[1023]; + page_directory[0] = buffer; + asm volatile("invlpg 0xFFC00000" :: + : "memory"); + return table; +} + +void load_address_space(physaddr_t table) +{ + asm volatile("mov %0, %%cr3" + : + : "r"(table) + : "memory"); +} + +int map_page(struct page_stack_t *page_stack, void *page, physaddr_t frame, int flags) +{ + if ((size_t)page % page_size != 0 || frame % page_size != 0) + { + return S_OUT_OF_BOUNDS; + } + size_t table_index = (size_t)page / page_size; + size_t directory_index = table_index / (page_size / sizeof(struct page_table_entry_t)); + if (!page_directory[directory_index].present) + { + physaddr_t new_table = reserve_page(page_stack); + if (new_table == S_OUT_OF_MEMORY) + { + return S_OUT_OF_MEMORY; + } + page_directory[directory_index].physicalAddress = new_table >> page_bits; + page_directory[directory_index].present = 1; + page_directory[directory_index].usermode = 0; + page_directory[directory_index].rw = 1; + } + page_tables[table_index].physicalAddress = frame >> 12; + page_tables[table_index].present = 1; + page_tables[table_index].usermode = 1; + page_tables[table_index].rw = 1; + asm volatile("invlpg (%0)" + : + : "r"(page) + : "memory"); + return S_OK; +} + +physaddr_t unmap_page(void *page) +{ + if ((size_t)page % page_size != 0) + { + return S_OUT_OF_BOUNDS; + } + size_t table_index = (size_t)page / page_size; + size_t directory_index = table_index / (page_size / sizeof(struct page_table_entry_t)); + if (!page_directory[directory_index].present || !page_tables[table_index].present) + { + return S_OUT_OF_BOUNDS; + } + else + { + physaddr_t frame = page_tables[table_index].physicalAddress << page_bits; + memset(&page_tables[table_index], 0, sizeof(struct page_table_entry_t)); + asm volatile("invlpg (%0)" + : + : "r"(page) + : "memory"); + return frame; + } +} \ No newline at end of file diff --git a/src/x86/msr.c b/src/x86/msr.c new file mode 100644 index 0000000..4182a2d --- /dev/null +++ b/src/x86/msr.c @@ -0,0 +1,17 @@ +#include "msr.h" + +void read_msr(enum msr_id_t msr_addr, uint64_t *value) +{ + uint64_t v; + asm volatile("rdmsr" + : "=edx:eax" (v) + : "ecx" (msr_addr)); + *value = v; +} + +void write_msr(enum msr_id_t msr_addr, uint64_t *value) +{ + uint64_t v = *value; + asm volatile("wrmsr" + :: "ecx"(msr_addr), "A"(v)); +} diff --git a/src/x86/msr.h b/src/x86/msr.h new file mode 100644 index 0000000..ea09f03 --- /dev/null +++ b/src/x86/msr.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +enum msr_id_t +{ + MSR_APIC_BASE = 0x1B +}; + +struct msr_apic_base_t +{ + uint64_t reserved_1 : 8; + uint64_t bsp : 1; + uint64_t reserved_2 : 1; + uint64_t x2apic_enable : 1; + uint64_t apic_global_enable : 1; + uint64_t apic_base : 52; +}; + +void read_msr(enum msr_id_t msr_addr, uint64_t *value); + +void write_msr(enum msr_id_t msr_addr, uint64_t *value); diff --git a/src/x86/multiboot2.c b/src/x86/multiboot2.c new file mode 100644 index 0000000..c692b5f --- /dev/null +++ b/src/x86/multiboot2.c @@ -0,0 +1,55 @@ +#include "multiboot2.h" +#include "stdio.h" +#include "string.h" + +void *read_multiboot_table(struct boot_info_t *boot_info, void *table) +{ + uint32_t *int_table = (uint32_t *)table; + switch (*int_table) + { + case MB_END_TAG: + return NULL; + case MB_MEMORY_MAP: ; + unsigned int tag_size = ((struct multiboot2_memory_map_t*) table)->size - 16; + unsigned int entry_size = ((struct multiboot2_memory_map_t*) table)->entry_size; + struct multiboot2_map_entry_t *entry = &((struct multiboot2_memory_map_t*) table)->entries; + while(tag_size) + { + unsigned int entry_type = + entry->type == MB_AVAILABLE ? M_AVAILABLE + : (entry->type == MB_DEFECTIVE ? M_DEFECTIVE + : M_UNAVAILABLE); + insert_region(&boot_info->map, entry->base, entry->length, entry_type); + entry = (struct multiboot2_map_entry_t*) ((void*) entry + entry_size); + tag_size -= entry_size; + } + break; + case MB_MODULE: + if(boot_info->module_count < 8) + { + boot_info->modules[boot_info->module_count].start = ((struct multiboot2_module_t*) table)->start; + boot_info->modules[boot_info->module_count].end = ((struct multiboot2_module_t*) table)->end; + strcpy(boot_info->modules[boot_info->module_count].str, ((struct multiboot2_module_t*) table)->str); + insert_region(&boot_info->map, + ((struct multiboot2_module_t*) table)->start, + ((struct multiboot2_module_t*) table)->end - ((struct multiboot2_module_t*) table)->start, + M_UNAVAILABLE); + boot_info->module_count++; + } + else + { + printf("WARNING: Too many modules, must skip one.\n"); + } + break; + case MB_BOOT_COMMAND: + strcpy(boot_info->parameters, &((struct multiboot2_string_t*) table)->str); + break; + case MB_BOOTLOADER: + strcpy(boot_info->bootloader, &((struct multiboot2_string_t*) table)->str); + break; + default: + break; + } + size_t size = (int_table[1] + 7) - ((int_table[1] + 7) % 8); + return table + size; +} diff --git a/src/x86/multiboot2.h b/src/x86/multiboot2.h new file mode 100644 index 0000000..ce65ddb --- /dev/null +++ b/src/x86/multiboot2.h @@ -0,0 +1,84 @@ +#pragma once + +#include "memorymap.h" +#include "module.h" +#include +#include + +#define module_limit 8 + +enum multiboot2_tag_types +{ + MB_END_TAG = 0, + MB_BOOT_COMMAND = 1, + MB_BOOTLOADER = 2, + MB_MODULE = 3, + MB_MEMORY_INFO = 4, + MB_BIOS_BOOT_DEVICE = 5, + MB_MEMORY_MAP = 6, + MB_VBE = 7, + MB_FRAMEBUFFER = 8, + MB_ELF_SYMBOLS = 9, + MB_APM = 10, + MB_EFI32_SYSTEM_TABLE = 11, + MB_EFI64_SYSTEM_TABLE = 12, + MB_SMBIOS = 13, + MB_ACPI10_RSDP = 14, + MB_ACPT20_RSDP = 15, + MB_NETOWRK = 16, + MB_EFI_MEMORY_MAP = 17, + MB_EFI_BOOT_SERVICES = 18, + MB_EFI32_IMAGE = 19, + MB_EFI64_IMAGE = 20, + MB_LOAD_ADDRESS = 21 +}; + +enum multiboot2_memory_types +{ + MB_AVAILABLE = 1, + MB_ACPI = 3, + MB_DEFECTIVE = 5 +}; + +struct multiboot2_string_t +{ + uint32_t type; + uint32_t size; + char str; +}; + +struct multiboot2_module_t +{ + uint32_t type; + uint32_t size; + uint32_t start; + uint32_t end; + char str; +}; + +struct multiboot2_map_entry_t +{ + uint64_t base; + uint64_t length; + uint32_t type; +}; + +struct multiboot2_memory_map_t +{ + uint32_t type; + uint32_t size; + uint32_t entry_size; + uint32_t entry_version; + struct multiboot2_map_entry_t entries; +}; + +struct boot_info_t +{ + char *bootloader; + char *parameters; + size_t module_count; + struct memory_map_t map; + struct module_t modules[module_limit]; +}; + +void *read_multiboot_table(struct boot_info_t *boot_info, void *table); diff --git a/src/x86/multiboot2header.S b/src/x86/multiboot2header.S deleted file mode 100755 index 050df1c..0000000 --- a/src/x86/multiboot2header.S +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Define constants for the multiboot header. See Multuboot 2 Specifications for details. - */ -.set align, 1<<0 -.set meminfo, 1<<1 -.set magic, 0xE85250D6 -.set arch, 0 -.set headerLength, _multibootHeaderEnd - _multibootHeaderStart -.set checksum, -(magic + arch + headerLength) - -.set tagNotOptional, 0 - -.set tagInfoRequestType, 1 -.set tagInfoRequestSize, _multibootInfoTagEnd - _multibootInfoTagStart -.set requestBootCommand, 1 -.set requestBootLoaderName, 2 -.set requestBootModules, 3 -.set requestMemoryInfo, 4 -.set requestBootDevice, 5 -.set requestMemoryMap, 6 - -.set tagAddressType, 2 -.set tagAddressSize, 24 -.set tagAddressHeaderLocation, LOAD_START -.set tagAddressLoadStart, LOAD_START -.set tagAddressLoadEnd, LOAD_END -.set tagAddressBSSEnd, BSS_END - -.set tagEntryType, 3 -.set tagEntrySize, 12 -.set tagEntryAddress, _start - (0xFF900000 - 0x100000) - -.set tagModuleAlignType, 6 -.set tagModuleAlignSize, 8 - -/* - * Each multiboot tag must be 8-byte aligned, or GRUB will not be able to read the header. - */ -.align 8 -_multibootHeaderStart: - -.long magic -.long arch -.long headerLength -.long checksum - -.align 8 - -_multibootInfoTagStart: -.short tagInfoRequestType -.short tagNotOptional -.long tagInfoRequestSize -.long requestBootCommand -.long requestBootLoaderName -.long requestBootModules -.long requestMemoryInfo -.long requestBootDevice -.long requestMemoryMap -_multibootInfoTagEnd: - -.align 8 - -.short tagAddressType -.short tagNotOptional -.long tagAddressSize -.long tagAddressHeaderLocation -.long tagAddressLoadStart -.long tagAddressLoadEnd -.long tagAddressBSSEnd - -.align 8 - -.short tagEntryType -.short tagNotOptional -.long tagEntrySize -.long tagEntryAddress - -.align 8 - -.short tagModuleAlignType -.short tagNotOptional -.long tagModuleAlignSize - -.align 8 - -/* - * Terminate list of multiboot header tags. - * Ending tag has type = 0, flags = 0, size = 8 - */ -.long 0 -.long 8 - -_multibootHeaderEnd: - diff --git a/src/x86/pagetableentry.cpp b/src/x86/pagetableentry.cpp deleted file mode 100755 index b07241f..0000000 --- a/src/x86/pagetableentry.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - * PageTableEntry.cpp - * - * Created on: May 22, 2019 - * Author: nathan - */ - -#include "pagetableentry.hpp" - -namespace kernel { - -static_assert(sizeof(PageTableEntry) == 4, "PTE structure is the wrong size!"); - -PageTableEntry::PageTableEntry() { - this->present = 0; - this->rw = 0; - this->usermode = 0; - this->writeThrough = 0; - this->cacheDisable = 0; - this->accessed = 0; - this->dirty = 0; - this->pat = 0; - this->global = 0; - this->shared = 0; - this->ignored = 0; - this->physicalAddress = 0; -} - -bool PageTableEntry::getAccessed() const { - return accessed == 1; -} - -bool PageTableEntry::getCacheDisable() const -{ - return cacheDisable == 1; -} - -void PageTableEntry::setCacheDisable(bool cacheDisable) -{ - this->cacheDisable = cacheDisable ? 1 : 0; -} - -bool PageTableEntry::getDirty() const -{ - return dirty == 1; -} - -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; -} - -physaddr_t PageTableEntry::setPhysicalAddress(physaddr_t physicalAddress) -{ - this->physicalAddress = physicalAddress >> 12; - return this->physicalAddress << 12; -} - -bool PageTableEntry::getPresent() const -{ - return present == 1; -} - -void PageTableEntry::setPresent(bool present) -{ - this->present = present ? 1 : 0; -} - -bool PageTableEntry::getRw() const -{ - return rw == 1; -} - -void PageTableEntry::setRw(bool rw) -{ - 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); -} - -PageTableEntry PageTableEntry::operator=(PageTableEntry rhs) -{ - uint32_t* iThis = (uint32_t*) this; - uint32_t* iThat = (uint32_t*) &rhs; - *iThis = *iThat; - return rhs; -} - -} diff --git a/src/x86/pagetableentry.hpp b/src/x86/pagetableentry.hpp deleted file mode 100755 index aa9fb8d..0000000 --- a/src/x86/pagetableentry.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef SRC_PAGETABLEENTRY_H_ -#define SRC_PAGETABLEENTRY_H_ - -#include -#include "../systypes.hpp" - -namespace kernel { - -class PageTableEntry { -public: - PageTableEntry(); - bool getAccessed() const; - bool getCacheDisable() const; - void setCacheDisable(bool cacheDisable); - bool getDirty() const; - bool getGlobal() const; - void setGlobal(bool global); - bool getPat() const; - void setPat(bool pat); - physaddr_t getPhysicalAddress() const; - physaddr_t setPhysicalAddress(physaddr_t physicalAddress); - bool getPresent() const; - void setPresent(bool present); - bool getRw() const; - void setRw(bool rw); - bool getShared() const; - void setShared(bool shared); - bool getUsermode() const; - void setUsermode(bool usermode); - bool getWriteThrough() const; - void setWriteThrough(bool writeThrough); - physaddr_t operator=(physaddr_t rhs); - PageTableEntry operator=(PageTableEntry 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; -}; - -} - -#endif diff --git a/src/x86/pio.S b/src/x86/pio.S deleted file mode 100644 index 7681ee0..0000000 --- a/src/x86/pio.S +++ /dev/null @@ -1,13 +0,0 @@ -.global outb -outb: - mov 4(%esp), %dx - mov 8(%esp), %al - out %al, %dx - ret - -.global inb -inb: - mov 4(%esp), %dx - xor %eax, %eax - in %dx, %al - ret \ No newline at end of file diff --git a/src/x86/pio.hpp b/src/x86/pio.hpp deleted file mode 100644 index 68aed33..0000000 --- a/src/x86/pio.hpp +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef PIO_H -#define PIO_H - -extern "C" void outb(short port, char data); - -extern "C" char inb(short port); - -#endif \ No newline at end of file diff --git a/src/x86/putc.c b/src/x86/putc.c new file mode 100644 index 0000000..854751f --- /dev/null +++ b/src/x86/putc.c @@ -0,0 +1,68 @@ +#include "stdio.h" +#include + +enum vga_color_t { + VGA_COLOR_BLACK = 0, + VGA_COLOR_BLUE = 1, + VGA_COLOR_GREEN = 2, + VGA_COLOR_CYAN = 3, + VGA_COLOR_RED = 4, + VGA_COLOR_MAGENTA = 5, + VGA_COLOR_BROWN = 6, + VGA_COLOR_LIGHT_GREY = 7, + VGA_COLOR_DARK_GREY = 8, + VGA_COLOR_LIGHT_BLUE = 9, + VGA_COLOR_LIGHT_GREEN = 10, + VGA_COLOR_LIGHT_CYAN = 11, + VGA_COLOR_LIGHT_RED = 12, + VGA_COLOR_LIGHT_MAGENTA = 13, + VGA_COLOR_LIGHT_BROWN = 14, + VGA_COLOR_WHITE = 15, +}; + +__attribute__ ((packed)) +struct cell_t +{ + char c; + char fg : 4; + char bg : 4; +}; + +struct cell_t *screen = (struct cell_t*)0xFF8B8000; +size_t cursor = 0; + +const size_t tab_width = 4; +const size_t line_width = 80; + +int putchar(int c) +{ + switch(c) + { + case '\n': + cursor += line_width; + cursor -= cursor % line_width; + break; + case '\t': + cursor += tab_width; + cursor -= cursor % tab_width; + break; + case '\r': + cursor -= line_width - 1; + cursor += line_width - (cursor % line_width); + break; + default: + screen[cursor].c = (char) c; + cursor++; + } + return c; +} + +int puts(const char *str) +{ + while(*str) + { + putchar(*str); + str++; + } + return 0; +} \ No newline at end of file diff --git a/src/x86/quark_x86.c b/src/x86/quark_x86.c new file mode 100644 index 0000000..0b6ec8c --- /dev/null +++ b/src/x86/quark_x86.c @@ -0,0 +1,102 @@ +#include "kernel.h" +#include "pageallocator.h" +#include "multiboot2.h" +#include "memorymap.h" +#include "apic.h" +#include "interrupts.h" +#include "msr.h" +#include "stdio.h" +#include "string.h" +#include "module.h" +#include "isr.h" +#include +#include + +extern int _kernel_end; + +struct apic_registers_t volatile *apic_registers; + +int startPaging(uint32_t *directory, uint32_t *table, uint32_t *identityTable) +{ + for (int i = 0; i < 1024; i++) + { + uint32_t pte = i * 4096 + 3; + table[i] = pte; + identityTable[i] = pte; + } + directory[0] = ((uint32_t)identityTable) + 3; + directory[1022] = ((uint32_t)table) + 3; + directory[1023] = ((uint32_t)directory) + 3; + asm("mov %0, %%cr3" + : + : "r"(directory)); + asm("mov %%cr0, %%eax \n" + "or $0x80010000, %%eax \n" + "mov %%eax, %%cr0" + : + : + : "eax"); + return 0; +} + +int initialize(void *multiboot_info) +{ + static struct interrupt_descriptor_t idt[256]; + static struct page_stack_t page_stack; + static struct kernel_t kernel; + struct memory_region_t map_array[16]; + char bootloader_name[64]; + char kernel_parameters[64]; + struct boot_info_t boot_info = { + .bootloader = bootloader_name, + .parameters = kernel_parameters, + .module_count = 0, + .map = { + .array = map_array, + .size = 0, + .capacity = 16}}; + multiboot_info += 8; + while (multiboot_info != NULL) + { + multiboot_info = read_multiboot_table(&boot_info, multiboot_info); + } + insert_region(&boot_info.map, 0, 1 << 22, M_UNAVAILABLE); + printf("Type\t\tLocation\t\tSize\n"); + for (size_t i = 0; i < boot_info.map.size && boot_info.map.array[i].size > 0; i++) + { + printf("%i\t\t\t%08x\t\t%u\n", boot_info.map.array[i].type, boot_info.map.array[i].location, boot_info.map.array[i].size); + } + page_stack.base_pointer = (physaddr_t*)0xFFC00000; + page_stack.stack_pointer = (physaddr_t*)0xFFC00000; + page_stack.limit_pointer = (physaddr_t*)0xFF900000; + initialize_page_stack(&page_stack, &boot_info.map, 4096); + for(int i = 0; i < boot_info.module_count; i++) + { + load_module(&kernel, &boot_info.modules[i]); + } + // TODO: setup IDT + memset(idt, 0, sizeof(struct interrupt_descriptor_t) * 256); + create_interrupt_descriptor(&idt[EXCEPTION_DIV_BY_0], (void*)isr_division_by_zero, INTERRPUT_INT32, 0); + create_interrupt_descriptor(&idt[EXCEPTION_GPF], (void*)isr_gp_fault, INTERRPUT_INT32, 0); + create_interrupt_descriptor(&idt[EXCEPTION_PAGE_FAULT], (void*)isr_page_fault, INTERRPUT_INT32, 0); + create_interrupt_descriptor(&idt[EXCEPTION_DOUBLE_FAULT], (void*)isr_double_fault, INTERRPUT_INT32, 0); + create_interrupt_descriptor(&idt[ISR_AP_START], (void*)isr_ap_start, INTERRPUT_INT32, 0); + create_interrupt_descriptor(&idt[ISR_SYSCALL], (void*)isr_syscall, INTERRPUT_INT32, 0); + lidt(idt); + + // TODO: setup APIC + asm volatile( + "mov $0xFF, %%al;" + "outb %%al, $0xA1;" + "outb %%al, $0x21;" + ::: "al" + ); + apic_enable(); + struct msr_apic_base_t msr; + read_msr(MSR_APIC_BASE, (uint64_t*)&msr); + msr.apic_base = (size_t) &_kernel_end >> 12; + write_msr(MSR_APIC_BASE, (uint64_t*)&msr); + printf("MSR_APIC_BASE: %016x\n", *((uint32_t*)&msr)); + apic_registers = (struct apic_registers_t*) (msr.apic_base << 12); + // TODO: enter first process +}