Merge pull request #3 from ngiddings/migrate-to-c

Migrate to c
This commit is contained in:
Nathan Giddings
2021-04-15 05:53:07 -05:00
committed by GitHub
75 changed files with 1687 additions and 3079 deletions

View File

@@ -4,18 +4,17 @@
AC_PREREQ([2.69])
AC_INIT([quark-kernel], [pre-alpha])
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
AC_CONFIG_SRCDIR([src/allocator.cpp])
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

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 PHYSADDR_H
#define PHYSADDR_H
#pragma once
#include <stdint.h>
#include <stddef.h>
#if defined __i386__ || __arm__
typedef uint32_t physaddr_t;
@@ -11,5 +9,3 @@ typedef uint64_t physaddr_t;
#else
typedef uint64_t physaddr_t;
#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,15 +1,18 @@
noinst_PROGRAMS = quark-kernel
quark_kernel_SOURCES = module.cpp util.cpp memorymap.cpp memoryregion.cpp pageallocator.cpp allocator.cpp scheduler.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/mmap.cpp \
x86/tty.cpp \
x86/interrupts.cpp \
x86/multiboot2.cpp \
x86/initialize.cpp \
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

View File

@@ -1,44 +0,0 @@
#include "elf.hpp"
#include "util.hpp"
kernelns::ELF::ELF()
{
this->m_fileLocation = (void*) NULL;
}
kernelns::ELF::ELF(void* location)
{
this->m_fileLocation = location;
}
void* kernelns::ELF::entry()
{
Header* fileHeader = (Header*) m_fileLocation;
return fileHeader->entry;
}
int kernelns::ELF::validate()
{
Header* fileHeader = (Header*) m_fileLocation;
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 kernelns::ELF::load()
{
Header* fileHeader = (Header*) m_fileLocation;
ProgramHeader* programHeader = (ProgramHeader*) ((size_t) m_fileLocation + fileHeader->phoffset);
int count = (int) fileHeader->phcount;
for(int i = 0; i < count; i++)
{
if((SegmentType) programHeader->type != Load)
continue;
memcpy(programHeader->vaddr, m_fileLocation + programHeader->offset, programHeader->filesize);
}
return 0;
}

View File

@@ -1,142 +0,0 @@
#ifndef ELF_H
#define ELF_H
#include "systypes.hpp"
namespace kernelns
{
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();
ELF(void* location);
void* entry();
int validate();
int load();
private:
void* m_fileLocation;
};
}
#endif

View File

@@ -1,98 +0,0 @@
#ifndef SCHEDULER_H
#define SCHEDULER_H
#include <stddef.h>
#include "process.hpp"
namespace kernelns
{
template<class T>
class Heap
{
public:
Heap()
{
}
Heap(T** array, size_t maxSize)
{
m_array = array;
m_size = 0;
m_limit = maxSize;
}
T* extractMin()
{
if(m_size == 0)
return nullptr;
m_size--;
T* p = m_array[0];
m_array[0] = m_array[m_size];
heapify(0);
return p;
}
Status insert(T* n)
{
if(m_size == m_limit)
return Status::NoMemory;
size_t i = m_size;
m_size++;
while(i > 0 && *m_array[(i - 1) / 2] > *n)
{
m_array[i] = m_array[(i - 1) / 2];
i = (i - 1) / 2;
}
m_array[i] = n;
return Status::OK;
}
void remove(T* 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;
}
}
}
private:
void heapify(size_t index)
{
if(i * 2 + 1 >= m_size)
return;
if (*m_array[i * 2 + 1] <= *m_array[i] && *m_array[i * 2 + 1] <= *m_array[i * 2 + 2])
{
T 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 * 2 + 2] <= *m_array[i] && *m_array[i * 2 + 2] <= *m_array[i * 2 + 1])
{
T buffer = m_array[i];
m_array[i] = m_array[i * 2 + 2];
m_array[i * 2 + 2] = buffer;
heapify(i * 2 + 2);
}
}
T** m_array;
size_t m_size, m_limit;
};
};
#endif

View File

@@ -1,27 +0,0 @@
#ifndef INTERRUPTS_H
#define INTERRUPTS_H
namespace kernelns
{
class Interrupts
{
public:
static const unsigned int MAX_SYSCALL_ID = 31;
Interrupts();
void enable();
void disable();
void addSyscall(unsigned int id, void* function);
private:
void* syscalls[MAX_SYSCALL_ID + 1];
};
}
#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,31 +0,0 @@
#include "kernel.hpp"
int Kernel::allocateRegion(void* page, size_t length, int flags)
{
char* ptr = (char*) page;
for(int i = (int) length; i > 0; i -= mmgr.getPageSize())
{
physaddr_t frame = pageAllocator.allocate(mmgr.getPageSize());
if(frame != 0)
mmgr.mapPage(page, reserveFrame(), flags);
else
return -1;
ptr += mmgr.getPageSize();
}
return 0;
}
void Kernel::freeRegion(void* page, size_t length)
{
char* ptr = (char*) page;
for(int i = (int) length; i > 0; i -= mmgr.getPageSize())
{
pageAllocator.free(mmgr.unmapPage((void*) ptr), mmgr.getPageSize());
ptr += mmgr.getPageSize();
}
}
int Kernel::mapRegion(void* page, physaddr_t frame, size_t length, int flags)
{
}

View File

@@ -1,156 +0,0 @@
#ifndef KERNEL_H
#define KERNEL_H
#include "pageallocator.hpp"
#include "memorymanager.hpp"
#include "memorymap.hpp"
#include "sharedblock.hpp"
#include "process.hpp"
#include "systypes.hpp"
using namespace kernelns;
class Kernel
{
public:
void* malloc(size_t size);
void free(void* ptr);
/**
* @brief Maps a region of pages starting at virtual address 'page' with
* length 'length'. Allocates each mapped frame and any necessary page
* tables. This method does not perform any checks before overwriting page
* tables; it is the responsibility of the caller to ensure that the
* operation is safe to perform.
*
* @param page The virtual address of the first page to map
* @param length The size in bytes of the region to map
* @param flags The flags to apply to each page
*
* @returns zero upon success, nonzero on failure
*/
int allocateRegion(void* page, size_t length, int flags);
/**
* @brief Unmaps and frees a region of mapped pages starting at virtual
* address 'page' with length 'length'. Does not free any page tables
* that are made redundant by this operation. It is the responsibility
* of the caller to ensure that all pages in the specified region are
* mapped and should be returned to the page allocator.
*
* @param page The virtual address of the first page to free
* @param length The size in bytes of the region to free
*/
void freeRegion(void* page, size_t length);
/**
* @brief Maps a contiguous region of pages to a contiguous region of
* frames. Allocates new page tables as needed. All pages will share
* the same flags.
*
* @param page The virtual address of the first page to map
* @param frame The physical address of the first frame to map to
* @param length The size in bytes of the region to map
* @param flags The flags to apply to each page
*
* @returns zero upon success, nonzero on failure
*/
int mapRegion(void* page, physaddr_t frame, size_t length, int flags);
/**
* @brief Unmaps a region of pages; does not return them to the page
* allocator.
*
* @param page The virtual address of the first page to unmap
* @param length The size in bytes of the region to unmap
*/
void unmapRegion(void* page, size_t length);
/**
* @brief Create a Shared Block object
*
* @param length
* @param flags
* @returns The ID of the
*/
unsigned int createSharedBlock(size_t length, int flags);
/**
* @brief Get the shared memory block referred to by 'id'
*
* @param id
* @returns a reference
*/
const SharedBlock& getSharedBlock(unsigned int id);
/**
* @brief Create a new process
*
* @param imageBlockID
* @return Process&
*/
Process& createProcess(unsigned int imageBlockID);
/**
* @brief Get the process object corresponsing to 'pid'
*
* @param pid id of the process to fetch
* @returns a reference to the requested process
*/
Process& getProcess(unsigned int pid);
/**
* @brief Get the current active process object.
*
* @returns a reference to the active process
*/
Process& getActiveProcess();
/**
* @brief Puts the current active process back on the run queue, and sets
* the active process to the next one selected by the scheduler.
*
* @returns a reference to the new active process
*/
Process& yieldActiveProcess();
/**
* @brief Puts the current active process to sleep, and sets the active
* process to the next one selected by the scheduler.
*
* @returns a reference to the new active process
*/
Process& sleepActiveProcess();
/**
* @brief Terminates the current active process, freeing all its resources,
* and activates the next process selected by the scheduler.
*
* @return Process&
*/
Process& terminateActiveProcess();
/**
* @brief Terminates the process with id 'pid', freeing all its resources.
* If it holds any shared blocks which are not held by any other process,
* those blocks will be freed.
*
* @param pid id of the process to terminate
*/
void terminateProcess(unsigned int pid);
private:
PageAllocator& pageAllocator;
MemoryManager& mmgr;
MemoryMap& memoryMap;
};
extern Kernel kernel;
#endif

View File

@@ -1,55 +0,0 @@
#ifndef MEMORYMANAGER_H
#define MEMORYMANAGER_H
#include "systypes.hpp"
class MemoryManager
{
public:
/**
* @brief Returns the size of a single page on the present platform.
*
* @return the size in bytes of a single page
*/
virtual unsigned int getPageSize() const = 0;
/**
* Allocates space for a new top-level page table, and initializes it to
* point only to the kernel's page tables.
*
* @returns the physical address of the new top-level page table
*/
virtual physaddr_t createAddressSpace() = 0;
/**
* Loads the given top-level page table(s).
*
* @param table the top-level page table to load
*/
virtual void loadAddressSpace(physaddr_t table) = 0;
/**
* Maps a single page to a single frame. Allocates a new page table if one
* does not exist for that frame.
*
* @param page the virtual address of the page to map
* @param frame the physical address of the frame to map to
* @param flags flags to apply to the entry
*
* @returns zero upon success, nonzero on failure
*/
virtual int mapPage(void* page, physaddr_t frame, int flags) = 0;
/**
* Deletes the page table entry for the specified page. Does not deallocate
* redundant page tables or modify higher level tables; these are cleaned up
* after the owning process ends.
*
* @param page the virtual address of the page to unmap
*/
virtual physaddr_t unmapPage(void* page) = 0;
};
#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,172 +0,0 @@
#include "memorymap.hpp"
using namespace kernelns;
MemoryMap::MemoryMap()
{
this->m_entries = 0;
}
MemoryMap::MemoryMap(MemoryMap& copy)
{
for(int i = 0; i < copy.m_entries; i++)
m_map[i] = copy[i];
this->m_entries = copy.m_entries;
}
const MemoryRegion& MemoryMap::operator[](size_t index) const
{
return m_map[index];
}
size_t MemoryMap::size() const
{
return m_entries;
}
size_t MemoryMap::totalMemory() const
{
size_t sum = 0;
for(int i = 0; i < m_entries; i++)
{
sum += m_map[i].getSize();
}
return sum;
}
size_t MemoryMap::totalMemory(unsigned int type) const
{
size_t sum = 0;
for(int i = 0; i < m_entries; i++)
{
if(m_map[i].getType() == type)
sum += m_map[i].getSize();
}
return sum;
}
bool MemoryMap::overlaps(const MemoryRegion& region) const
{
for(int i = 0; i < m_entries; i++)
{
if(m_map[i].overlaps(region))
return true;
}
return false;
}
bool MemoryMap::contains(const MemoryRegion& region) const
{
for(int i = 0; i < m_entries; i++)
{
if(m_map[i].contains(region) && m_map[i].getType() == region.getType())
return true;
}
return false;
}
void MemoryMap::insertEntry(const MemoryRegion& region)
{
simpleInsert(region);
unsigned int i = 0;
while(i != invalidIndex)
i = trim(i);
}
void MemoryMap::insertEntry(physaddr_t location, size_t size, unsigned int type)
{
insertEntry(MemoryRegion(location, size, type));
}
void MemoryMap::remove(unsigned int index)
{
for(unsigned int i = index; i < (m_entries - 1); i++)
{
m_map[i] = m_map[i+1];
}
m_entries--;
}
void MemoryMap::simpleInsert(const MemoryRegion& region)
{
MemoryRegion newRegion(region);
unsigned int i = 0;
while(i < m_entries)
{
if(newRegion < m_map[i])
{
MemoryRegion buffer = newRegion;
newRegion = m_map[i];
m_map[i] = buffer;
}
i++;
}
m_map[i] = newRegion;
m_entries++;
}
void MemoryMap::simpleInsert(physaddr_t location, size_t size, unsigned int type)
{
simpleInsert(MemoryRegion(location, size, type));
}
unsigned int MemoryMap::trim(unsigned int index)
{
if(index + 1 >= m_entries)
return invalidIndex;
MemoryRegion& left = m_map[index];
MemoryRegion& right = m_map[index+1];
if(left.overlaps(right))
{
if(left.getType() == right.getType())
{
left = MemoryRegion(left.getLocation(),
(right.getEnd() > left.getEnd() ? right.getEnd() : left.getEnd()) - left.getLocation(),
left.getType());
remove(index + 1);
return index;
}
else if(left.getType() < right.getType())
{
if(right.contains(left))
{
remove(index);
return index;
}
else if(left.getEnd() <= right.getEnd())
{
left.truncateRight(right.getLocation());
return index + 1;
}
else
{
MemoryRegion newRight(right.getEnd(), left.getEnd() - right.getEnd(), left.getType());
left.truncateRight(right.getLocation());
if(left.getSize() == 0)
remove(index);
simpleInsert(newRight);
return index + 2;
}
}
else
{
if(left.contains(right))
{
remove(index + 1);
return index;
}
else
{
right.truncateLeft(left.getEnd());
return index + 1;
}
}
}
else if(left.bordersLeft(right) && left.getType() == right.getType())
{
left = MemoryRegion(left.getLocation(), right.getEnd() - left.getLocation(), left.getType());
remove(index + 1);
return index;
}
return index + 1;
}

View File

@@ -1,152 +0,0 @@
#ifndef MEMORYMAP_H
#define MEMORYMAP_H
#include "systypes.hpp"
#include "memoryregion.hpp"
namespace kernelns
{
class MemoryMap
{
public:
MemoryMap();
MemoryMap(MemoryMap& copy);
const MemoryRegion& operator[](size_t index) const;
/**
* @return The number of memory regions described by this object
*/
size_t size() const;
/**
* @brief Get the total amount of memory described by this memory map.
* Since no two regions may overlap, this is equivalent to the sum of the
* size of each memory region stored in this object.
*
* @return The total amount of memory described by this memory map.
*/
size_t totalMemory() const;
/**
* @brief Get the total amount of memory of a specified type described by
* this memory map. Since no two regions overlap, this is equivalent to the
* sum of the size of each memory region stored in this object whose type
* is equal to `type`.
*
* @param type The type of memory region to count
* @return The total amount of memory of the specified type
*/
size_t totalMemory(unsigned int type) const;
/**
* @brief Checks if `region` overlaps any memory region contained in this
* memory map.
*
* @param region
* @return true if, for any region `k` in this map, `k.overlaps(region)`.
* @return false if there is no region in this map where `k.overlaps(region)`.
*/
bool overlaps(const MemoryRegion& region) const;
/**
* @brief Checks if `region` is contained an any memory region in this map
* with the same type as `region`.
*
* @param region
* @return true if, for any region `k` in this map, `k.contains(region)
* && k.getType() == region.getType()`.
* @return false if the condition above is not true
*/
bool contains(const MemoryRegion& region) const;
/**
* @brief Adds `region` into the memory map. Adjusts the map as necessary
* so that no regions overlap. Regions of higher type take precedence over
* regions with lower types; therefore, the lower typed regions are trimmed
* or deleted where they overlap with higher typed regions. Adjacent or
* overlapping regions with identical types are merged.
*
* @param region The memory region to insert
*/
void insertEntry(const MemoryRegion& region);
/**
* @brief Overload of `insertEntry()`. @see insertRegion(const MemoryRegion&).
*
* @param location
* @param size
* @param type
*/
void insertEntry(physaddr_t location, size_t size, unsigned int type);
private:
/**
* @brief Removes the element at `index` in `m_map`. All objects located
* after that index are moved accordingly.
*
* @param index Locatation of the object to delete
*/
void remove(unsigned int index);
/**
* @brief Inserts a copy of `region` into `m_map`. The new element is
* inserted such that `m_map` is sorted in ascending order. Overlapping
* elements are not trimmed.
*
* @param region The memory region to insert
*/
void simpleInsert(const MemoryRegion& region);
/**
* @brief Overload of `simpleInsert(const MemoryRegion& region)`.
*
* @param location
* @param size
* @param type
*/
void simpleInsert(physaddr_t location, size_t size, unsigned int type);
/**
* @brief If `m_map[index].overlaps(m_map[index+1])`, the two elements are
* modified so that they no longer overlap. The following rules apply:
*
* 1. This memory map will describe the same set of locations before and
* after performing this operation.
*
* 2. Adjacent regions of the same type are merged into a single region.
*
* 3. Where two regions of differing types overlap, the higher type takes
* precedence. The region of the lower type is truncated, split, or deleted
* so as to not overlap the region of the higher type.
*
* 4. This operation is local: only `m_map[index]` and `m_map[index+1]` are
* modified (although if a region must be split, a new region will be
* inserted at the location `index+2`).
*
* This function has no effect if `index+1 >= m_entries`, or if
* `m_map[index]` does not overlap the `m_map[index+1]`.
*
* @param index The location of the region to trim.
*
* @return The index of the rightmost region affected.
*/
unsigned int trim(unsigned int index);
static const unsigned int maxEntries = 16;
static const unsigned int invalidIndex = 0xFFFF;
MemoryRegion m_map[maxEntries];
size_t m_entries;
};
}
#endif

View File

@@ -1,128 +0,0 @@
#include "memoryregion.hpp"
MemoryRegion::MemoryRegion()
{
m_location = 0;
m_size = 0;
m_type = 0;
}
MemoryRegion::MemoryRegion(const MemoryRegion& copy)
{
m_location = copy.m_location;
m_size = copy.m_size;
m_type = copy.m_type;
}
MemoryRegion::MemoryRegion(physaddr_t location, size_t size, unsigned int type)
{
m_location = location;
m_size = size;
m_type = (size_t) type;
}
const MemoryRegion& MemoryRegion::operator=(const MemoryRegion& rhs)
{
m_location = rhs.m_location;
m_size = rhs.m_size;
m_type = rhs.m_type;
return rhs;
}
bool MemoryRegion::operator==(const MemoryRegion& rhs) const
{
return (m_location == rhs.m_location) && (m_size == rhs.m_size);
}
bool MemoryRegion::operator!=(const MemoryRegion& rhs) const
{
return (m_location != rhs.m_location) || (m_size != rhs.m_size);
}
bool MemoryRegion::operator<(const MemoryRegion& rhs) const
{
return (m_location < rhs.m_location) || ((m_location == rhs.m_location) && (m_size < rhs.m_size));
}
bool MemoryRegion::operator>(const MemoryRegion& rhs) const
{
return (m_location > rhs.m_location) || ((m_location == rhs.m_location) && (m_size > rhs.m_size));
}
bool MemoryRegion::operator<=(const MemoryRegion& rhs) const
{
return (m_location < rhs.m_location) || ((m_location == rhs.m_location) && (m_size <= rhs.m_size));
}
bool MemoryRegion::operator>=(const MemoryRegion& rhs) const
{
return (m_location > rhs.m_location) || ((m_location == rhs.m_location) && (m_size >= rhs.m_size));
}
physaddr_t MemoryRegion::getLocation() const
{
return m_location;
}
size_t MemoryRegion::getSize() const
{
return m_size;
}
unsigned int MemoryRegion::getType() const
{
return m_type;
}
physaddr_t MemoryRegion::getEnd() const
{
return m_location + m_size;
}
bool MemoryRegion::contains(const MemoryRegion& r) const
{
return contains(r.m_location, r.m_size);
}
bool MemoryRegion::contains(physaddr_t location, size_t size) const
{
return (location >= m_location) &&
(location + size <= m_location + m_size);
}
bool MemoryRegion::overlaps(const MemoryRegion& r) const
{
if(r.m_location < m_location)
return r.m_location + r.m_size > m_location;
else
return r.m_location < getEnd();
}
bool MemoryRegion::bordersLeft(const MemoryRegion& right) const
{
return getEnd() == right.m_location;
}
bool MemoryRegion::bordersRight(const MemoryRegion& left) const
{
return m_location == left.m_location + left.m_size;
}
bool MemoryRegion::borders(const MemoryRegion& r) const
{
return bordersLeft(r) || bordersRight(r);
}
void MemoryRegion::truncateLeft(physaddr_t left)
{
m_size = getEnd() - left;
m_location = left;
}
void MemoryRegion::truncateRight(physaddr_t right)
{
if(right > m_location)
m_size = right - m_location;
else
m_size = 0;
}

View File

@@ -1,87 +0,0 @@
#ifndef MEMORYBLOCK_H
#define MEMORYBLOCK_H
#include "systypes.hpp"
class MemoryRegion
{
public:
MemoryRegion();
MemoryRegion(const MemoryRegion& copy);
MemoryRegion(physaddr_t location, size_t size, unsigned int type);
const MemoryRegion& operator=(const MemoryRegion& rhs);
/**
* @brief Tests whether this object describes the same region of memory
* as rhs, irrespective of type.
*
* @param rhs The object to compare to
* @return true if and only if the location and size of the two regions are equal
* @return false if the two regions have differing locations or differing sizes
*/
bool operator==(const MemoryRegion& rhs) const;
/**
* @brief Tests whether this object describes a different region of memory
* than rhs, irrespective of type.
*
* @param rhs The object to compare to
* @return true if the two regions have differing locations or differing sizes
* @return false if and only if the location and size of the two regions are equal
*/
bool operator!=(const MemoryRegion& rhs) const;
/**
* @brief
*
* @param rhs
* @return true
* @return false
*/
bool operator<(const MemoryRegion& rhs) const;
bool operator>(const MemoryRegion& rhs) const;
bool operator<=(const MemoryRegion& rhs) const;
bool operator>=(const MemoryRegion& rhs) const;
physaddr_t getLocation() const;
size_t getSize() const;
unsigned int getType() const;
physaddr_t getEnd() const;
bool contains(const MemoryRegion& r) const;
bool contains(physaddr_t location, size_t size) const;
bool overlaps(const MemoryRegion& r) const;
bool bordersLeft(const MemoryRegion& right) const;
bool bordersRight(const MemoryRegion& left) const;
bool borders(const MemoryRegion& r) const;
void truncateLeft(physaddr_t left);
void truncateRight(physaddr_t right);
private:
physaddr_t m_location;
size_t m_size;
unsigned int m_type;
};
#endif

View File

@@ -1,11 +0,0 @@
#ifndef MEMORYTYPE_H
#define MEMORYTYPE_H
enum class MemoryType
{
Available = 1,
Unavailable = 2,
Defective = 3
};
#endif

View File

@@ -1,38 +0,0 @@
#include "message.hpp"
Message::Message()
{
m_sender = 0;
m_type = 0;
m_args[0] = 0;
m_args[1] = 0;
m_args[2] = 0;
}
Message::Message(const Message& copy)
{
m_sender = copy.m_sender;
m_type = copy.m_type;
m_args[0] = copy.m_args[0];
m_args[1] = copy.m_args[1];
m_args[2] = copy.m_args[2];
}
Message::Message(unsigned int sender, unsigned int type,
unsigned long arg1, unsigned long arg2, unsigned long arg3)
{
m_sender = sender;
m_type = type;
m_args[0] = arg1;
m_args[1] = arg2;
m_args[2] = arg3;
}
Message& Message::operator=(const Message& rhs)
{
m_sender = rhs.m_sender;
m_type = rhs.m_type;
m_args[0] = rhs.m_args[0];
m_args[1] = rhs.m_args[1];
m_args[2] = rhs.m_args[2];
}

View File

@@ -1,59 +0,0 @@
#ifndef MESSAGE_H
#define MESSAGE_H
struct Message
{
/**
* @brief Default constructor. Initializes all members to 0.
*
*/
Message();
/**
* @brief Copy constructor.
*
* @param copy
*/
Message(const Message& copy);
/**
* @brief Construct a new Message object.
*
* @param sender
* @param type
* @param arg1
* @param arg2
* @param arg3
*/
Message(unsigned int sender, unsigned int type,
unsigned long arg1, unsigned long arg2, unsigned long arg3);
/**
* @brief Copy the contents of `rhs` to this object.
*
* @param rhs
* @return Message&
*/
Message& operator=(const Message& rhs);
/**
* @brief PID of the process that generated this message.
*/
unsigned int m_sender;
/**
* @brief Context-specific parameter which indicates to the receiver how
* the arguments are to be interpreted.
*/
unsigned int m_type;
/**
* @brief Arguments of this message. The meaning of these values depend on
* context, as well as the values of `m_sender` and `m_type`.
*/
unsigned long m_args[3];
};
#endif

View File

@@ -1,31 +0,0 @@
#ifndef MMAP_H
#define MMAP_H
#include "pageallocator.hpp"
#define MMAP_RW 0x01
#define MMAP_EXEC 0x02
#define MMAP_SHARED 0x04
namespace kernelns
{
int mmap(void* start, size_t length, int flags);
int mmap(void* start, physaddr_t p_start, size_t length, int flags);
int mapPage(void* start, physaddr_t p_start, int flags);
int munmap(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,39 +0,0 @@
#include "module.hpp"
#include "util.hpp"
using namespace kernelns;
Module::Module()
{
m_start = 0;
m_end = 0;
m_command = NULL;
}
Module::Module(physaddr_t start, physaddr_t end, const char* command)
{
m_start = start;
m_end = end;
m_command = new char[strlen(command) + 1];
strcpy(m_command, command);
}
Module::~Module()
{
delete[] m_command;
}
physaddr_t Module::getStart() const
{
return m_start;
}
physaddr_t Module::getEnd() const
{
return m_end;
}
const char* Module::getCommand() const
{
return m_command;
}

View File

@@ -1,39 +0,0 @@
#ifndef ELF_H
#define ELF_H
#include <stdint.h>
#include "systypes.hpp"
namespace kernelns
{
class Module
{
public:
Module();
Module(physaddr_t start, physaddr_t end, const char* command);
~Module();
physaddr_t getStart() const;
physaddr_t getEnd() const;
const char* getCommand() const;
private:
physaddr_t m_start;
physaddr_t m_end;
char* m_command;
};
}
#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,43 +0,0 @@
#ifndef __MEMORYALLOCATOR_H_
#define __MEMORYALLOCATOR_H_
#include <stddef.h>
#include "systypes.hpp"
namespace kernelns
{
/**
* Interface for a physical memory allocator.
*/
class PageAllocator
{
public:
/**
* Allocate a single page, returning its physical address. Upon failure,
* returns an error code such that the least signifigant byte is nonzero.
*/
virtual physaddr_t next() = 0;
/**
* Frees a single page that has previously been allocated.
*/
virtual void free(physaddr_t location) = 0;
/**
* @returns the total number of free blocks of memory.
*/
virtual size_t freeBlocks() const = 0;
/**
* @returns the total number of blocks managed by this memory
* allocator.
*/
virtual size_t getMemorySize() const = 0;
};
}
#endif

View File

@@ -1,52 +0,0 @@
#include "pageallocatorstack.hpp"
#include "memorytype.hpp"
using namespace kernelns;
PageAllocatorStack::PageAllocatorStack(physaddr_t *stackBase, physaddr_t *stackTop, size_t frameSize, const MemoryMap& memoryMap)
{
m_base = stackBase;
m_top = stackTop;
m_stack = m_base;
for(int i = 0; i < memoryMap.size(); i++)
{
if((MemoryType) memoryMap[i].getType() == MemoryType::Available)
{
for(int j = 0; j < memoryMap[i].getSize() / frameSize; j++)
{
free(memoryMap[i].getLocation() + j * frameSize);
}
}
}
}
physaddr_t PageAllocatorStack::next()
{
if(m_stack < m_base)
{
physaddr_t frame = *m_stack;
*m_stack = (physaddr_t) 0;
m_stack++;
return frame;
}
return (physaddr_t) -1;
}
void PageAllocatorStack::free(physaddr_t location)
{
if(m_stack > m_top)
{
m_stack--;
*m_stack = location;
}
}
size_t PageAllocatorStack::freeBlocks() const
{
return m_base - m_stack;
}
size_t PageAllocatorStack::getMemorySize() const
{
return m_totalSize;
}

View File

@@ -1,34 +0,0 @@
#ifndef PAGEALLOCATORSTACK_H
#define PAGEALLOCATORSTACK_H
#include "pageallocator.hpp"
#include "memorymap.hpp"
namespace kernelns
{
class PageAllocatorStack : public PageAllocator
{
public:
PageAllocatorStack(physaddr_t *stackBase, physaddr_t *stackTop, size_t frameSize, const MemoryMap& memoryMap);
virtual physaddr_t next();
virtual void free(physaddr_t location);
virtual size_t freeBlocks() const;
virtual size_t getMemorySize() const;
private:
size_t m_totalSize;
physaddr_t *m_stack, *m_base, *m_top;
};
}
#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,54 +0,0 @@
#ifndef PROCESS_H
#define PROCESS_H
#include <stddef.h>
#include "message.hpp"
namespace kernelns
{
class Process
{
public:
size_t priority;
void* stack;
Process();
unsigned int getID() const;
bool map(void* location, size_t size);
/**
* @brief If the specified region is mapped and does not overlap a shared
* or private block, or the kernel, removes that region from the process's
* internal memory map. If the specified region overlaps an unmapped region,
* a shared or private block, or the kernel, the object goes unmodified.
* This method does not affect the page tables in any way, only the process's
* internal bookkeeping.
*
* @param location
* @param size
* @return true if the memory map was sucessfully updated
* @return false if the memory map was not modified
*/
bool unmap(void* location, size_t size);
bool hasSharedBlock(unsigned int blockID) const;
bool hasPhysicalBlock(unsigned int blockID) const;
void pushMessage(Message* message);
Message* popMessage();
private:
};
}
#endif

View File

@@ -1,18 +0,0 @@
#ifndef SHAREDBLOCK_H
#define SHAREDBLOCK_H
#include "memoryregion.hpp"
class SharedBlock : public MemoryRegion
{
public:
unsigned int getFlags() const;
private:
unsigned int m_flags;
};
#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,93 +0,0 @@
#include "syscalls.hpp"
#include "kernel.hpp"
#include "memorytype.hpp"
int mmap(void* location, size_t length, int flags)
{
if(kernel.getActiveProcess().map(location, length))
{
if(kernel.allocateRegion(location, length, flags))
return 0;
else if(kernel.getActiveProcess().unmap(location, length))
return 1;
kernel.terminateActiveProcess();
}
return kernel.allocateRegion(location, length, flags);
}
int munmap(void* location, size_t length)
{
if(kernel.getActiveProcess().unmap(location, length))
{
kernel.freeRegion(location, length);
return 0;
}
return 1;
}
unsigned int createSharedBlock(void* location, size_t length, int flags)
{
unsigned int blockID = kernel.createSharedBlock(length, flags);
if(blockID > 0)
{
const SharedBlock& block = kernel.getSharedBlock(blockID);
kernel.mapRegion(location, block.getLocation(), length, flags);
// TODO: add block to current process
// TODO: perform safety checks
}
return blockID;
}
int aquireSharedBlock(void* location, unsigned int id)
{
const SharedBlock& block = kernel.getSharedBlock(id);
kernel.mapRegion(location, block.getLocation(), block.getSize(), block.getFlags());
// TODO: (somehow) handle invalid ids -- possibly hard while using references
// TODO: add block to current process
// TODO: perform safety checks
return 0;
}
int releaseSharedBlock(int id)
{
// (0) Check that process actually posesses block
// (1) Get virtual address of block
// (2) Unmap block
// (3) Delete block if no one posesses it anymore
return 0;
}
int querySharedBlock(void* info, int id)
{
// TODO: define struct for block info
}
int aquirePhysicalBlock(void* location, physaddr_t physicalAddress, size_t length)
{
return 0;
}
int releasePhysicalBlock(int id)
{
return 0;
}
int sendMessage(unsigned int recipient, const Message* message)
{
Message* copy = new Message(*message);
copy->m_sender = kernel.getActiveProcess().getID();
kernel.getProcess(recipient).pushMessage(copy);
return 0;
}
int receiveMessage(Message* buffer)
{
if(buffer == nullptr)
return 1;
Message* message = kernel.getActiveProcess().popMessage();
if(message == nullptr)
return 1;
*buffer = *message;
delete message;
return 0;
}

View File

@@ -1,28 +0,0 @@
#ifndef SYSCALLS_H
#define SYSCALLS_H
#include <stddef.h>
#include "systypes.hpp"
#include "message.hpp"
int mmap(void* location, size_t length, int flags);
int munmap(void* location, size_t length);
unsigned int createSharedBlock(void* location, size_t length, int flags);
int aquireSharedBlock(void* location, unsigned int id);
int releaseSharedBlock(int id);
int querySharedBlock(void* info, int id);
int aquirePhysicalBlock(void* location, physaddr_t physicalAddress, size_t length);
int releasePhysicalBlock(int id);
int sendMessage(unsigned int recipient, const Message* message);
int receiveMessage(Message* buffer);
#endif

View File

@@ -1,8 +0,0 @@
#ifndef SYSTYPES_H
#define SYSTYPES_H
#include "types/physaddr.h"
#include "types/status.h"
#include "types/handle.h"
#endif

View File

@@ -1,8 +0,0 @@
#ifndef HANDLE_H
#define HANDLE_H
#include <stdint.h>
typedef uint64_t handle_t;
#endif

View File

@@ -1,11 +0,0 @@
#ifndef STATUS_H
#define STATUS_H
enum class Status
{
OK = 0,
BadArgument,
NoMemory
};
#endif

View File

@@ -1,165 +0,0 @@
#include <stdint.h>
#include "util.hpp"
#include "kernel.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;
}
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;
}
void* malloc(size_t size)
{
return kernel.malloc(size);
}
void* calloc(size_t count, size_t size)
{
void* ptr = malloc(count * size);
if(ptr != nullptr)
memset(malloc(count * size), 0, count * size);
return ptr;
}
void* realloc(void* ptr, size_t size)
{
void* n = kernel.malloc(size);
if(n != nullptr)
{
memmove(n, ptr, size);
free(ptr);
}
return n;
}
void free(void* p)
{
kernel.free(p);
}
void __cxa_pure_virtual()
{
// do nothing
}
void* operator new(size_t size)
{
return malloc(size);
}
void* operator new[](size_t size)
{
return malloc(size);
}
void operator delete(void* p)
{
free(p);
}
void operator delete[](void* p)
{
free(p);
}

View File

@@ -1,56 +0,0 @@
#ifndef UTIL_H
#define UTIL_H
#include <stddef.h>
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);
extern "C" int strlen(const char* str);
extern "C" char* strcpy(char* destination, const char* source);
extern "C" void* malloc(size_t size);
extern "C" void* calloc(size_t count, size_t size);
extern "C" void* realloc(void* ptr, size_t size);
extern "C" void free(void* p);
extern "C" void __cxa_pure_virtual();
void* operator new(size_t size);
void* operator new[](size_t size);
void operator delete(void* p);
void operator delete[](void* p);
inline void* operator new(size_t, void *p)
{
return p;
}
inline void* operator new[](size_t, void *p)
{
return p;
}
inline void operator delete(void *, void *)
{
}
inline void operator delete[](void *, void *)
{
}
#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

@@ -124,7 +124,7 @@ _tempPgDir:
_tempIdentityMap:
.skip 4096
_tempPgTable:
.skip 8192
.skip 4096
_bootCmdLine:
.skip 64
@@ -143,6 +143,9 @@ memory_map:
.global _start
.type _start, @function
_start:
cli
# This platform reqires a Multiboot2 bootloader.
cmp $0x36d76289, %eax
jne .err
@@ -212,12 +215,6 @@ _start:
push %ebx
call initialize
# mov $_bootCmdLine, %eax
# push %eax
# Call main function
# call main
.err:
cli
2: hlt

View File

@@ -1,61 +0,0 @@
#include <stdint.h>
#include "multiboot2.hpp"
#include "tty.hpp"
#include "../mmap.hpp"
#include "../util.hpp"
#include "../memorytype.hpp"
using namespace kernelns;
extern int _kernelEnd;
extern "C"
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;
}
extern "C"
int initialize(void* multibootInfo)
{
size_t heapSize = 0xFFC00000 - (size_t) &_kernelEnd;
int log = 0;
for(; heapSize > 1; log++)
heapSize >>= 1;
heapSize <<= log;
//new(&State::allocator) Allocator((void*) (0xFFC00000 - heapSize), heapSize, 64);
Multiboot2Info bootInfo(multibootInfo);
if(!bootInfo.isValid())
return 1;
bootInfo.getMemoryMap().insertEntry(0, 4 * 1024 * 1024, (unsigned int) MemoryType::Unavailable);
//new(&State::config) SystemInfo(bootInfo.getMemoryMap(), bootInfo.getCommandLine());
TTY tty((char*) 0xFF8B8000);
tty << "Type\t\tLocation\t\tSize\n";
for(size_t i = 0; i < bootInfo.getMemoryMap().size() && bootInfo.getMemoryMap()[i].getSize() > 0; i++)
{
tty << (int) bootInfo.getMemoryMap()[i].getType() << "\t\t\t";
tty << (void*) bootInfo.getMemoryMap()[i].getLocation() << "\t\t";
tty << (int) bootInfo.getMemoryMap()[i].getSize() << "\n";
}
// TODO: Initialize page allocator
// TODO: Initialize process queue, add entry for each module
return 0;
}

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,169 +0,0 @@
#include "../interrupts.hpp"
#include <stdint.h>
#include <stddef.h>
class InterruptDescriptor
{
public:
enum Type
{
TASK32 = 5,
TRAP32 = 15,
INT32 = 14,
TRAP16 = 7,
INT16 = 6
};
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;
}
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 present()
{
return m_present == 1;
}
void present(bool present)
{
m_present = present ? 1 : 0;
}
Type type()
{
return (Type) m_type;
}
void type(Type type)
{
m_type = (unsigned int) type;
}
unsigned int dpl()
{
return m_dpl;
}
void dpl(unsigned int dpl)
{
m_dpl = dpl;
}
void* operator=(void* rhs)
{
uint32_t offset = (uint32_t) rhs;
m_offset1 = (uint16_t) offset;
m_offset2 = (offset >> 16);
return 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;
};
struct IDTInfo
{
uint16_t size;
void* location;
};
InterruptDescriptor idt[256];
void lidt()
{
IDTInfo idtInfo;
idtInfo.size = sizeof(idt) - 1;
idtInfo.location = (void*) &idt;
asm("lidt (%0)"
:
: "r" (&idtInfo));
}
__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)
{
asm("hlt");
}
__attribute__ ((interrupt))
void syscallHandler(void* frame)
{
}
kernelns::Interrupts::Interrupts()
{
for(unsigned int i = 0; i <= MAX_SYSCALL_ID; i++)
syscalls[i] = (void*) NULL;
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();
}
void kernelns::Interrupts::enable()
{
asm("sti");
}
void kernelns::Interrupts::disable()
{
asm("cli");
}
void kernelns::Interrupts::addSyscall(unsigned int id, void* function)
{
if(id <= MAX_SYSCALL_ID)
syscalls[id] = function;
}

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

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

@@ -38,5 +38,5 @@ SECTIONS
_heapLocation = 0xFFB00000;
_heapSize = 0x100000;
_kernelStart = VIRTUAL_BASE;
_kernelEnd = VIRTUAL_BASE + (4096 * IMAGE_SIZE);
_kernel_end = VIRTUAL_BASE + (4096 * IMAGE_SIZE);
}

View File

@@ -1,31 +0,0 @@
#include "memorymanagerx86.hpp"
unsigned int MemoryManagerx86::getPageSize() const
{
return pageSize;
}
physaddr_t MemoryManagerx86::createAddressSpace()
{
if(((size_t) table & 0xFFF) != 0)
return -1;
PageTableEntry* newDirectory = (PageTableEntry*) table;
newDirectory[1022] = m_pageDirectory[1022];
newDirectory[1023] = m_pageDirectory[1023];
return 0;
}
void MemoryManagerx86::loadAddressSpace(physaddr_t table)
{
}
int MemoryManagerx86::mapPage(void *page, physaddr_t frame, int flags)
{
}
physaddr_t MemoryManagerx86::unmapPage(void *page)
{
}

View File

@@ -1,29 +0,0 @@
#ifndef MEMORYMANAGERX86_H
#define MEMORYMANAGERX86_H
#include "../memorymanager.hpp"
#include "pagetableentry.hpp"
class MemoryManagerx86 : public MemoryManager
{
public:
virtual unsigned int getPageSize() const;
virtual physaddr_t createAddressSpace();
virtual void loadAddressSpace(physaddr_t table);
virtual int mapPage(void* page, physaddr_t frame, int flags);
virtual physaddr_t unmapPage(void* page);
private:
static const unsigned int pageSize = 4096;
PageTableEntry *m_pageTables, *m_pageDirectory;
};
#endif

View File

@@ -1,292 +0,0 @@
#include "../mmap.hpp"
#include "../kernelstate.hpp"
class PageTableEntry {
public:
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 getAccessed() const
{
return accessed == 1;
}
bool getCacheDisable() const
{
return cacheDisable == 1;
}
void setCacheDisable(bool cacheDisable)
{
this->cacheDisable = cacheDisable ? 1 : 0;
}
bool getDirty() const
{
return dirty == 1;
}
bool getGlobal() const
{
return global == 1;
}
void setGlobal(bool global)
{
this->global = global ? 1 : 0;
}
bool getPat() const
{
return pat == 1;
}
void setPat(bool pat)
{
this->pat = pat ? 1 : 0;
}
physaddr_t getPhysicalAddress() const
{
physaddr_t physicalAddress = this->physicalAddress;
return physicalAddress << 12;
}
physaddr_t setPhysicalAddress(physaddr_t physicalAddress)
{
this->physicalAddress = physicalAddress >> 12;
return this->physicalAddress << 12;
}
bool getPresent() const
{
return present == 1;
}
void setPresent(bool present)
{
this->present = present ? 1 : 0;
}
bool getRw() const
{
return rw == 1;
}
void setRw(bool rw)
{
this->rw = rw ? 1 : 0;
}
bool getShared() const
{
return shared == 1;
}
void setShared(bool shared)
{
this->shared = shared ? 1 : 0;
}
bool getUsermode() const
{
return usermode == 1;
}
void setUsermode(bool usermode)
{
this->usermode = usermode ? 1 : 0;
}
bool getWriteThrough() const
{
return writeThrough == 1;
}
void setWriteThrough(bool writeThrough)
{
this->writeThrough = writeThrough ? 1 : 0;
}
physaddr_t operator=(physaddr_t rhs)
{
return setPhysicalAddress(rhs);
}
PageTableEntry operator=(PageTableEntry rhs)
{
uint32_t* iThis = (uint32_t*) this;
uint32_t* iThat = (uint32_t*) &rhs;
*iThis = *iThat;
return 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;
};
int kernelns::mmap(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 = State::pageAllocator.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 = State::pageAllocator.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 kernelns::mmap(void* start, physaddr_t p_start, size_t length, int flags)
{
if((size_t) start % 4096 != 0 || p_start % 4096 != 0)
return -1;
physaddr_t page = p_start;
for(int i = (int) length; i > 0; i -= 4096)
{
if(mapPage(start, page, flags) != 0)
return -1;
page += 4096;
}
return 0;
}
int kernelns::mapPage(void* start, physaddr_t p_start, int flags)
{
if((size_t) start % 4096 != 0 || p_start % 4096 != 0)
return -1;
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
size_t tableIndex = (size_t) start / 4096;
physaddr_t page = p_start;
size_t directoryIndex = tableIndex / 1024;
if(!pageDirectory[directoryIndex].getPresent())
{
physaddr_t newPT = State::pageAllocator.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())
{
pageTables[tableIndex] = page;
pageTables[tableIndex].setPresent(true);
pageTables[tableIndex].setUsermode(false);
if(flags & MMAP_RW)
pageTables[tableIndex].setRw(true);
}
return 0;
}
int kernelns::munmap(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 kernelns::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 kernelns::getPhysicalAddress(void* addr)
{
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
size_t tableIndex = (size_t) addr / 4096;
return pageTables[tableIndex].getPhysicalAddress() + ((size_t) addr & 0xFFF);
}
int kernelns::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 kernelns::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;
}

View File

@@ -1,83 +0,0 @@
#include "multiboot2.hpp"
#include "../memorytype.hpp"
using namespace kernelns;
Multiboot2Info::Multiboot2Info(void* tableLocation)
{
m_commandLine = NULL;
m_bootloader = NULL;
m_moduleCount = 0;
uint32_t* ptr = (uint32_t*) tableLocation;
ptr += 2;
while(*ptr != 0)
{
if(*ptr == (uint32_t) Tag::BootCommand)
{
m_commandLine = &reinterpret_cast<TagString*>(ptr)->str;
}
else if(*ptr == (uint32_t) Tag::Bootloader)
{
m_bootloader = &reinterpret_cast<TagString*>(ptr)->str;
}
else if(*ptr == (uint32_t) Tag::MemoryMap)
{
unsigned int tagSize = reinterpret_cast<TagMemoryMap*>(ptr)->size - 16;
unsigned int entrySize = reinterpret_cast<TagMemoryMap*>(ptr)->entrySize;
MemoryMapEntry* entry = &reinterpret_cast<TagMemoryMap*>(ptr)->entries;
while(tagSize > 0)
{
unsigned int regionType =
(entry->type == (unsigned int) Multiboot2MemoryType::Available) ? (unsigned int) MemoryType::Available
: ((entry->type == (unsigned int) Multiboot2MemoryType::Defective) ? (unsigned int) MemoryType::Defective
: (unsigned int) MemoryType::Unavailable);
m_memmap.insertEntry(entry->base, entry->length, entry->type);
entry = (MemoryMapEntry*) (reinterpret_cast<char*>(entry) + entrySize);
tagSize -= entrySize;
}
}
else if(*ptr == (uint32_t) Tag::Module)
{
TagModule* moduleTag = reinterpret_cast<TagModule*>(ptr);
m_modules[m_moduleCount] = Module(moduleTag->start, moduleTag->end, &moduleTag->str);
m_memmap.insertEntry(moduleTag->start, moduleTag->end - moduleTag->start, (unsigned int) MemoryType::Unavailable);
}
unsigned int size = (ptr[1] + 7) - ((ptr[1] + 7) % 8);
ptr += size / sizeof(uint32_t);
}
}
Multiboot2Info::~Multiboot2Info()
{
}
bool Multiboot2Info::isValid() const
{
return true;
}
MemoryMap& Multiboot2Info::getMemoryMap()
{
return m_memmap;
}
const Module* Multiboot2Info::getModules() const
{
return m_modules;
}
unsigned int Multiboot2Info::getModuleCount() const
{
return m_moduleCount;
}
const char* Multiboot2Info::getCommandLine() const
{
return m_commandLine;
}
const char* Multiboot2Info::getBootloaderName() const
{
return m_bootloader;
}

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,112 +0,0 @@
#ifndef MULTIBOOT2_H
#define MULTIBOOT2_H
#include "../memorymap.hpp"
#include "../module.hpp"
namespace kernelns
{
class Multiboot2Info
{
public:
enum class Tag
{
BootCommand = 1,
Bootloader = 2,
Module = 3,
MemoryInfo = 4,
BIOSBootDevice = 5,
MemoryMap = 6,
VBE = 7,
Framebuffer = 8,
ELFSymbols = 9,
APM = 10,
EFI32SystemTable = 11,
EFI64SystemTable = 12,
SMBIOS = 13,
ACPI10RSDP = 14,
ACPT20RSDP = 15,
Network = 16,
EFIMemoryMap = 17,
EFIBootServices = 18,
EFI32Image = 19,
EFI64Image = 20,
LoadAddress = 21
};
enum class Multiboot2MemoryType
{
Available = 1,
ACPI = 3,
Defective = 5
};
struct TagString
{
uint32_t type;
uint32_t size;
char str;
};
struct TagModule
{
uint32_t type;
uint32_t size;
uint32_t start;
uint32_t end;
char str;
};
struct MemoryMapEntry
{
uint64_t base;
uint64_t length;
uint32_t type;
};
struct TagMemoryMap
{
uint32_t type;
uint32_t size;
uint32_t entrySize;
uint32_t entryVersion;
MemoryMapEntry entries;
};
Multiboot2Info(void* tableLocation);
~Multiboot2Info();
bool isValid() const;
MemoryMap& getMemoryMap();
const Module* getModules() const;
unsigned int getModuleCount() const;
const char* getCommandLine() const;
const char* getBootloaderName() const;
private:
Module m_modules[16];
unsigned int m_moduleCount;
MemoryMap m_memmap;
char* m_commandLine;
char* m_bootloader;
void* m_tableLocation;
};
}
#endif

View File

@@ -1,132 +0,0 @@
#include "pagetableentry.hpp"
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::getShared() const
{
return shared == 1;
}
void PageTableEntry::setShared(bool shared)
{
this->shared = shared ? 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;
}
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,83 +0,0 @@
#ifndef PAGETABLEENTRY_H
#define PAGETABLEENTRY_H
#include "../systypes.hpp"
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

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
}

View File

@@ -1,125 +0,0 @@
#include <stdbool.h>
#include "tty.hpp"
kernelns::TTY::TTY(char* vga)
{
this->vga = vga;
this->cursor = 0;
this->width = 0;
this->base = 10;
}
kernelns::TTY& kernelns::TTY::operator<<(kernelns::TTY::Format fmt)
{
switch(fmt)
{
case Binary:
base = 2;
break;
case Decimal:
base = 10;
break;
case Hex:
base = 16;
break;
}
}
kernelns::TTY& kernelns::TTY::operator<<(const char* str)
{
return printString(str);
}
kernelns::TTY& kernelns::TTY::operator<<(unsigned int n)
{
return printNumber(n, base, width);
}
kernelns::TTY& kernelns::TTY::operator<<(int n)
{
return printNumber((unsigned int) n, base, width);
}
kernelns::TTY& kernelns::TTY::operator<<(void* n)
{
return printNumber((unsigned int) n, 16, 8);
}
kernelns::TTY& kernelns::TTY::operator<<(char c)
{
return putChar(c);
}
void kernelns::TTY::setWidth(size_t width)
{
this->width = width;
}
size_t kernelns::TTY::getWidth()
{
return width;
}
void kernelns::TTY::clear()
{
for(int i = 0; i < 80*25; i++)
{
vga[i * 2] = ' ';
}
cursor = 0;
}
kernelns::TTY& kernelns::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;
}
kernelns::TTY& kernelns::TTY::printString(const char* str)
{
while(*str)
{
putChar(*str);
str++;
}
return *this;
}
kernelns::TTY& kernelns::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 kernelns
{
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