@@ -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
117
include/elf.h
Normal 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
18
include/kernel.h
Normal 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
27
include/memorymap.h
Normal 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
39
include/mmgr.h
Normal 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
10
include/module.h
Normal 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
75
include/pageallocator.h
Normal 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
55
include/priorityqueue.h
Normal 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
12
include/process.h
Normal 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
11
include/stdio.h
Normal 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
15
include/string.h
Normal 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);
|
||||
@@ -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;
|
||||
@@ -10,6 +8,4 @@ typedef uint32_t physaddr_t;
|
||||
typedef uint64_t physaddr_t;
|
||||
#else
|
||||
typedef uint64_t physaddr_t;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
9
include/types/status.h
Normal file
9
include/types/status.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
enum status_t
|
||||
{
|
||||
S_OK = 0,
|
||||
S_BAD_SYSCALL,
|
||||
S_OUT_OF_MEMORY,
|
||||
S_OUT_OF_BOUNDS
|
||||
};
|
||||
@@ -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
|
||||
|
||||
44
src/elf.cpp
44
src/elf.cpp
@@ -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;
|
||||
}
|
||||
142
src/elf.hpp
142
src/elf.hpp
@@ -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
|
||||
98
src/heap.hpp
98
src/heap.hpp
@@ -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
|
||||
@@ -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
11
src/kernel.c
Normal 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)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
156
src/kernel.hpp
156
src/kernel.hpp
@@ -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
|
||||
@@ -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
136
src/memorymap.c
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef MEMORYTYPE_H
|
||||
#define MEMORYTYPE_H
|
||||
|
||||
enum class MemoryType
|
||||
{
|
||||
Available = 1,
|
||||
Unavailable = 2,
|
||||
Defective = 3
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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];
|
||||
}
|
||||
@@ -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
|
||||
31
src/mmap.hpp
31
src/mmap.hpp
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
52
src/pageallocator.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
67
src/priorityqueue.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
100
src/stdio.c
Normal 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
110
src/string.c
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef SYSTYPES_H
|
||||
#define SYSTYPES_H
|
||||
|
||||
#include "types/physaddr.h"
|
||||
#include "types/status.h"
|
||||
#include "types/handle.h"
|
||||
|
||||
#endif
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef HANDLE_H
|
||||
#define HANDLE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint64_t handle_t;
|
||||
|
||||
#endif
|
||||
@@ -1,11 +0,0 @@
|
||||
#ifndef STATUS_H
|
||||
#define STATUS_H
|
||||
|
||||
enum class Status
|
||||
{
|
||||
OK = 0,
|
||||
BadArgument,
|
||||
NoMemory
|
||||
};
|
||||
|
||||
#endif
|
||||
165
src/util.cpp
165
src/util.cpp
@@ -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);
|
||||
}
|
||||
56
src/util.hpp
56
src/util.hpp
@@ -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
35
src/x86/apic.c
Normal 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
156
src/x86/apic.h
Normal 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);
|
||||
@@ -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
|
||||
|
||||
@@ -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
29
src/x86/interrupts.c
Normal 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;
|
||||
}
|
||||
@@ -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
54
src/x86/interrupts.h
Normal 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
41
src/x86/isr.c
Normal 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
19
src/x86/isr.h
Normal 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);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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
|
||||
292
src/x86/mmap.cpp
292
src/x86/mmap.cpp
@@ -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
123
src/x86/mmgr.c
Normal 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
17
src/x86/msr.c
Normal 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
22
src/x86/msr.h
Normal 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
55
src/x86/multiboot2.c
Normal 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;
|
||||
}
|
||||
@@ -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
84
src/x86/multiboot2.h
Normal 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);
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
68
src/x86/putc.c
Normal 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
102
src/x86/quark_x86.c
Normal 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
|
||||
}
|
||||
125
src/x86/tty.cpp
125
src/x86/tty.cpp
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user