Merge pull request #4 from ngiddings/pre-alpha

Pre alpha
This commit is contained in:
Nathan Giddings
2021-04-15 05:56:49 -05:00
committed by GitHub
74 changed files with 2006 additions and 2072 deletions

3
.gitignore vendored
View File

@@ -5,6 +5,8 @@ quark-kernel
autom4te.cache/ autom4te.cache/
.deps .deps
.dirstamp
.vscode
aclocal.m4 aclocal.m4
ar-lib ar-lib
compile compile
@@ -24,3 +26,4 @@ stamp-h1
rootfs/apps rootfs/apps
test/ test/
doc/

26
DEVELOPERS.md Normal file
View File

@@ -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]

View File

@@ -1 +1 @@
===Quark Kernel=== # Quark Kernel

View File

@@ -3,19 +3,18 @@
AC_PREREQ([2.69]) AC_PREREQ([2.69])
AC_INIT([quark-kernel], [pre-alpha]) AC_INIT([quark-kernel], [pre-alpha])
AM_INIT_AUTOMAKE([-Wall foreign]) AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
AC_CONFIG_SRCDIR([src/tty.cpp]) AC_CONFIG_SRCDIR([src/kernel.c])
AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_HEADERS([src/config.h])
# Checks for programs. # Checks for programs.
AC_PROG_CXX
AC_PROG_CC AC_PROG_CC
AM_PROG_AS AM_PROG_AS
AM_PROG_AR AM_PROG_AR
AC_PROG_RANLIB AC_PROG_RANLIB
# Checks for header files. # 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. # Checks for typedefs, structures, and compiler characteristics.
AC_CHECK_HEADER_STDBOOL AC_CHECK_HEADER_STDBOOL

117
include/elf.h Normal file
View File

@@ -0,0 +1,117 @@
#pragma once
#include "types/physaddr.h"
#include <stdint.h>
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

18
include/kernel.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#include "priorityqueue.h"
#include "module.h"
#include <stddef.h>
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));

27
include/memorymap.h Normal file
View File

@@ -0,0 +1,27 @@
#pragma once
#include "types/physaddr.h"
#include <stddef.h>
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);

39
include/mmgr.h Normal file
View File

@@ -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);

10
include/module.h Normal file
View File

@@ -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)];
};

75
include/pageallocator.h Normal file
View File

@@ -0,0 +1,75 @@
#pragma once
#include "memorymap.h"
#include "types/physaddr.h"
#include <stddef.h>
/**
* @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);

55
include/priorityqueue.h Normal file
View File

@@ -0,0 +1,55 @@
#pragma once
#include "process.h"
#include <stddef.h>
/**
* @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);

12
include/process.h Normal file
View File

@@ -0,0 +1,12 @@
#pragma once
#include <stddef.h>
struct process_state_t;
struct process_t
{
size_t priority;
struct process_state_t *state;
};

11
include/stdio.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include <stdarg.h>
int putchar(int c);
int puts(const char *str);
int printf(const char *format, ...);
int sprintf(char *str, const char *format, ...);

15
include/string.h Normal file
View File

@@ -0,0 +1,15 @@
#pragma once
#include <stddef.h>
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);

View File

@@ -1,8 +1,6 @@
#ifndef SYSTYPES_H #pragma once
#define SYSTYPES_H
#include <stdint.h> #include <stdint.h>
#include <stddef.h>
#if defined __i386__ || __arm__ #if defined __i386__ || __arm__
typedef uint32_t physaddr_t; typedef uint32_t physaddr_t;
@@ -11,5 +9,3 @@ typedef uint64_t physaddr_t;
#else #else
typedef uint64_t physaddr_t; typedef uint64_t physaddr_t;
#endif #endif
#endif

9
include/types/status.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
enum status_t
{
S_OK = 0,
S_BAD_SYSCALL,
S_OUT_OF_MEMORY,
S_OUT_OF_BOUNDS
};

View File

@@ -1,4 +1,3 @@
menuentry "Quark OS" { menuentry "Quark OS" {
multiboot2 /apps/quark-kernel multiboot2 /apps/quark-kernel
module2 /apps/test
} }

View File

@@ -1,19 +1,20 @@
noinst_PROGRAMS = quark-kernel 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_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 quark_kernel_LDFLAGS = -nostdlib
if x86 if x86
quark_kernel_SOURCES += x86/pagetableentry.cpp \ quark_kernel_SOURCES += x86/mmgr.c \
x86/mmap.cpp \ x86/putc.c \
x86/interrupts.cpp \ x86/multiboot2.c \
x86/inthandlers.cpp \ x86/interrupts.c \
x86/interruptdescriptor.cpp \ x86/apic.c \
x86/idt.S \ x86/isr.c \
x86/entry.S \ x86/msr.c \
x86/pio.S \ x86/quark_x86.c \
x86/multiboot2header.S x86/entry.S
quark_kernel_LDFLAGS += -T x86/linker.ld quark_kernel_LDFLAGS += -T x86/linker.ld
quark_kernel_DEPENDENCIES = x86/linker.ld quark_kernel_DEPENDENCIES = x86/linker.ld
endif endif

102
src/allocator.cpp Normal file
View File

@@ -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;
}

42
src/allocator.hpp Normal file
View File

@@ -0,0 +1,42 @@
#ifndef ALLOCATOR_H
#define ALLOCATOR_H
#include <stddef.h>
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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -1,142 +0,0 @@
#ifndef ELF_H
#define ELF_H
#include <stdint.h>
#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

View File

@@ -1,19 +0,0 @@
#ifndef INTERRUPTS_H
#define INTERRUPTS_H
namespace kernel
{
class Interrupts
{
public:
Interrupts();
void enable();
void disable();
};
}
#endif

11
src/kernel.c Normal file
View File

@@ -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)
{
}

View File

@@ -1,21 +0,0 @@
#ifndef KERNELSTATE_H
#define KERNELSTATE_H
#include <stddef.h>
#include "process.hpp"
namespace kernel
{
class State
{
public:
static const size_t MAX_PROCESSES = 2048;
};
}
#endif

136
src/memorymap.c Normal file
View File

@@ -0,0 +1,136 @@
#include "memorymap.h"
#include <stdbool.h>
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);
}
}

View File

@@ -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);
}

View File

@@ -1,61 +0,0 @@
#ifndef MEMORYMAP_H
#define MEMORYMAP_H
#include <stdint.h>
#include <stddef.h>
#include "systypes.hpp"
namespace kernel
{
class MemoryMap
{
public:
enum Type
{
AVAILABLE = 1,
ACPI = 3,
DEFECTIVE = 5
};
class Region
{
public:
physaddr_t getLocation();
size_t getSize();
Type getType();
bool contains(physaddr_t location, size_t size);
private:
physaddr_t location;
size_t size;
uint32_t type;
};
MemoryMap(Region* map, size_t entries);
Region& operator[](size_t index);
size_t size();
private:
Region* map;
size_t entries;
};
}
#endif

View File

@@ -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

View File

@@ -1,7 +0,0 @@
#ifndef MMGR_H
#define MMGR_H
#include "mmap.hpp"
#include "buddyallocator.hpp"
#endif

52
src/pageallocator.c Normal file
View File

@@ -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;
}
}
}

View File

@@ -1,55 +0,0 @@
#ifndef __MEMORYALLOCATOR_H_
#define __MEMORYALLOCATOR_H_
#include <stddef.h>
#include "systypes.hpp"
namespace kernel
{
/**
* Interface for a dymanic memory allocator.
*/
class MemoryAllocator
{
public:
/**
* Allocate a block of memory containing 'size' bytes. May round up
* depending on the implementation.
*/
virtual physaddr_t allocate(size_t size) = 0;
/**
* Free the region of memory starting at 'location' and containing
* 'size' bytes.
*/
virtual void free(physaddr_t location, size_t size) = 0;
/**
* @returns the total number of free blocks of memory.
*/
virtual size_t freeBlocks() const = 0;
/**
* @returns the size in blocks of the largest possible allocation that
* will not fail due to lack of memory.
*/
virtual size_t maxAllocationSize() const = 0;
/**
* @returns the size in bytes of a single block.
*/
virtual size_t getBlockSize() const = 0;
/**
* @returns the total number of blocks managed by this memory
* allocator.
*/
virtual size_t getMemorySize() const = 0;
};
}
#endif

67
src/priorityqueue.c Normal file
View File

@@ -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;
}

View File

@@ -1,36 +0,0 @@
#include <stddef.h>
#include <stdint.h>
#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";
}

View File

@@ -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);
}
}

View File

@@ -1,45 +0,0 @@
#ifndef SCHEDULER_H
#define SCHEDULER_H
#include <stddef.h>
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

100
src/stdio.c Normal file
View File

@@ -0,0 +1,100 @@
#include "stdio.h"
#include <stddef.h>
#include <stdbool.h>
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, ...)
{
}

110
src/string.c Normal file
View File

@@ -0,0 +1,110 @@
#include "string.h"
#include <stdbool.h>
#include <stdint.h>
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;
}

View File

@@ -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;
}

View File

@@ -1,33 +0,0 @@
#ifndef SYSTEMINFO_H
#define SYSTEMINFO_H
#include <stddef.h>
#include "systypes.hpp"
namespace kernel
{
class SystemInfo
{
public:
size_t getLowMemory();
size_t getHighMemory();
physaddr_t getKernelBase();
private:
size_t lowMemory;
size_t highMemory;
physaddr_t kernelBase;
};
}
#endif

View File

@@ -1,125 +0,0 @@
#include <stdbool.h>
#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;
}

View File

@@ -1,60 +0,0 @@
#ifndef TTY_H_
#define TTY_H_
#include <stddef.h>
namespace kernel
{
class TTY
{
public:
enum Format
{
Binary,
Decimal,
Hex
};
TTY(char* vga);
TTY& operator<<(Format fmt);
TTY& operator<<(const char* str);
TTY& operator<<(unsigned int n);
TTY& operator<<(int n);
TTY& operator<<(void* n);
TTY& operator<<(char c);
void setWidth(size_t width);
size_t getWidth();
void clear();
private:
TTY& printNumber(unsigned int n, size_t base, size_t width);
TTY& printString(const char* str);
TTY& putChar(char c);
char* vga;
int cursor;
size_t width;
size_t base;
};
}
#endif

View File

@@ -1,81 +0,0 @@
#include <stdint.h>
#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
}

View File

@@ -1,16 +0,0 @@
#ifndef UTIL_H
#define UTIL_H
#include <stddef.h>
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

35
src/x86/apic.c Normal file
View File

@@ -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];
}

156
src/x86/apic.h Normal file
View File

@@ -0,0 +1,156 @@
#pragma once
#include <stdint.h>
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);

View File

@@ -1,5 +1,98 @@
.section .multiboot .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 .section .rodata
@@ -31,7 +124,7 @@ _tempPgDir:
_tempIdentityMap: _tempIdentityMap:
.skip 4096 .skip 4096
_tempPgTable: _tempPgTable:
.skip 8192 .skip 4096
_bootCmdLine: _bootCmdLine:
.skip 64 .skip 64
@@ -50,181 +143,57 @@ memory_map:
.global _start .global _start
.type _start, @function .type _start, @function
_start: _start:
cli
# This platform reqires a Multiboot2 bootloader.
cmp $0x36d76289, %eax 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 # Push physical address of identity map
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
mov $_tempIdentityMap, %eax mov $_tempIdentityMap, %eax
sub $BASE_DIFF, %eax sub $BASE_DIFF, %eax
or $3, %eax push %eax
# Load the physical address of the page directory # Push physical address of page table
mov $_tempPgDir, %edi
sub $BASE_DIFF, %edi
# Save the PDE to the first element in the page directory
mov %eax, (%edi)
# Load the physical address of the temporary page table, and generate a PDE
mov $_tempPgTable, %eax mov $_tempPgTable, %eax
sub $BASE_DIFF, %eax sub $BASE_DIFF, %eax
or $3, %eax push %eax
# Save the PDE to the entry corresponding to 0xC0000000 # Push physical address of page directory
mov %eax, 4088(%edi) mov $_tempPgDir, %eax
sub $BASE_DIFF, %eax
push %eax
# Set the last entry in the page directory to point to the page directory itself # Load physical address of startPaging()
mov %edi, %eax mov $startPaging, %eax
or $3, %eax sub $BASE_DIFF, %eax
mov %eax, 4092(%edi)
# Load the physical address of the page directory into CR3 # Initialize paging
mov $_tempPgDir, %edi call *%eax
sub $BASE_DIFF, %edi
mov %edi, %cr3
# Enable paging
mov %cr0, %eax
or $0x80010000, %eax
mov %eax, %cr0
# Jump into mapped kernel binary # Jump into mapped kernel binary
lea 2f, %eax lea 1f, %eax
jmp *%eax jmp *%eax
2: 1:
# Delete PDE corresponding to identity map. We shouldn't need it anymore. # Delete PDE corresponding to identity map. We shouldn't need it anymore.
movl $0, (_tempIdentityMap) movl $0, (_tempIdentityMap)
# Reload page tables # Flush TLB
mov %cr3, %eax mov %cr3, %eax
mov %eax, %cr3 mov %eax, %cr3
# Initialize stack # Initialize stack in virtual memory
mov $stackTop, %esp mov $stackTop, %esp
# Load GPT
lgdt gdt_info lgdt gdt_info
# Load segment registers
jmp $8, $.ldcs jmp $8, $.ldcs
.ldcs: .ldcs:
mov $16, %ax mov $16, %ax
@@ -234,15 +203,21 @@ s_end:
mov %ax, %fs mov %ax, %fs
mov %ax, %ss mov %ax, %ss
mov $_bootCmdLine, %eax # Change EBX to point to the virtual address of the multiboot info
push %eax # If the new pointer is out-of-bounds, error
add $0xFF800000, %ebx
cmp $0xFF800000, %ebx
jl .err
cmp $0xFFC00000, %ebx
jge .err
# Call main function # Call initialize(void* multibootInfo)
call main push %ebx
call initialize
_err: .err:
cli cli
3: hlt 2: hlt
jmp 3b jmp 2b
.size _start, . - _start .size _start, . - _start

View File

@@ -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

View File

@@ -1,10 +0,0 @@
#ifndef IDT_H
#define IDT_H
#include "interruptdescriptor.hpp"
extern kernel::InterruptDescriptor idt[256];
extern "C" void _lidt();
#endif

View File

@@ -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;
}

View File

@@ -1,55 +0,0 @@
#ifndef INTERRUPTDESCRIPTOR_H
#define INTERRUPTDESCRIPTOR_H
#include <stdint.h>
namespace kernel
{
class InterruptDescriptor
{
public:
enum Type
{
TASK32 = 5,
TRAP32 = 15,
INT32 = 14,
TRAP16 = 7,
INT16 = 6
};
InterruptDescriptor();
InterruptDescriptor(void* handler, Type type, unsigned int dpl);
bool present();
void present(bool present);
Type type();
void type(Type type);
unsigned int dpl();
void dpl(unsigned int dpl);
void* operator=(void* rhs);
private:
uint16_t m_offset1;
uint16_t m_selector;
uint16_t m_zero : 8;
uint16_t m_type : 4;
uint16_t m_storage : 1;
uint16_t m_dpl : 2;
uint16_t m_present : 1;
uint16_t m_offset2;
};
}
#endif

29
src/x86/interrupts.c Normal file
View File

@@ -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;
}

View File

@@ -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");
}

54
src/x86/interrupts.h Normal file
View File

@@ -0,0 +1,54 @@
#pragma once
#include <stdint.h>
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);

View File

@@ -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;
}

View File

@@ -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

41
src/x86/isr.c Normal file
View File

@@ -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)
{
}

19
src/x86/isr.h Normal file
View File

@@ -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);

View File

@@ -33,4 +33,10 @@ SECTIONS
LOAD_END = ADDR(.data) + SIZEOF(.data) - (VIRTUAL_BASE - PHYSICAL_BASE); LOAD_END = ADDR(.data) + SIZEOF(.data) - (VIRTUAL_BASE - PHYSICAL_BASE);
BSS_END = ADDR(.bss) + SIZEOF(.bss) - (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; 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);
} }

View File

@@ -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;
}

123
src/x86/mmgr.c Normal file
View File

@@ -0,0 +1,123 @@
#include "mmgr.h"
#include "pageallocator.h"
#include "string.h"
#include "types/status.h"
#include <stdint.h>
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;
}
}

17
src/x86/msr.c Normal file
View File

@@ -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));
}

22
src/x86/msr.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include <stdint.h>
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);

55
src/x86/multiboot2.c Normal file
View File

@@ -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;
}

84
src/x86/multiboot2.h Normal file
View File

@@ -0,0 +1,84 @@
#pragma once
#include "memorymap.h"
#include "module.h"
#include <stddef.h>
#include <stdint.h>
#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);

View File

@@ -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:

View File

@@ -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;
}
}

View File

@@ -1,52 +0,0 @@
#ifndef SRC_PAGETABLEENTRY_H_
#define SRC_PAGETABLEENTRY_H_
#include <stdint.h>
#include "../systypes.hpp"
namespace kernel {
class PageTableEntry {
public:
PageTableEntry();
bool getAccessed() const;
bool getCacheDisable() const;
void setCacheDisable(bool cacheDisable);
bool getDirty() const;
bool getGlobal() const;
void setGlobal(bool global);
bool getPat() const;
void setPat(bool pat);
physaddr_t getPhysicalAddress() const;
physaddr_t setPhysicalAddress(physaddr_t physicalAddress);
bool getPresent() const;
void setPresent(bool present);
bool getRw() const;
void setRw(bool rw);
bool getShared() const;
void setShared(bool shared);
bool getUsermode() const;
void setUsermode(bool usermode);
bool getWriteThrough() const;
void setWriteThrough(bool writeThrough);
physaddr_t operator=(physaddr_t rhs);
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

View File

@@ -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

View File

@@ -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

68
src/x86/putc.c Normal file
View File

@@ -0,0 +1,68 @@
#include "stdio.h"
#include <stddef.h>
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;
}

102
src/x86/quark_x86.c Normal file
View File

@@ -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 <stdint.h>
#include <stddef.h>
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
}