3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,6 +5,8 @@ quark-kernel
|
||||
|
||||
autom4te.cache/
|
||||
.deps
|
||||
.dirstamp
|
||||
.vscode
|
||||
aclocal.m4
|
||||
ar-lib
|
||||
compile
|
||||
@@ -24,3 +26,4 @@ stamp-h1
|
||||
|
||||
rootfs/apps
|
||||
test/
|
||||
doc/
|
||||
26
DEVELOPERS.md
Normal file
26
DEVELOPERS.md
Normal file
@@ -0,0 +1,26 @@
|
||||
Notice: The kernel is still in early development. Some information in this file
|
||||
may be inaccurate. Please create an issue if this is the case.
|
||||
|
||||
# Porting
|
||||
|
||||
The kernel should be portable to most systems, provided they support paging
|
||||
and have sufficient memory. All platform-specific code belongs in an appropriately-named
|
||||
subdirectory inside src/. It must provide a linker script, startup code, and
|
||||
implement a set of functions required by the kernel.
|
||||
|
||||
The linker script must define the following symbols:
|
||||
- _pageMapLocation The location of the bitmap to be used by the page allocator.
|
||||
- _heapLocation The location of the kernel's heap.
|
||||
- _heapSize The size in bytes of the kernel's heap.
|
||||
- _kernelStart The linear address of the start of the kernel image.
|
||||
- _kernelEnd The first linear address after the end of the kernel image.
|
||||
|
||||
The startup code is required to enable paging and relocate the kernel if necessary. It also
|
||||
needs to provide a memory map to the kernel in the form of an array of MemoryMap::Region
|
||||
structures. It should then call main() with a pointer to the kernel command line as an argument.
|
||||
|
||||
In addition, the contents of mmap.hpp and interrupts.hpp must be implemented.
|
||||
|
||||
# Files
|
||||
|
||||
[TODO]
|
||||
@@ -3,19 +3,18 @@
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([quark-kernel], [pre-alpha])
|
||||
AM_INIT_AUTOMAKE([-Wall foreign])
|
||||
AC_CONFIG_SRCDIR([src/tty.cpp])
|
||||
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
|
||||
AC_CONFIG_SRCDIR([src/kernel.c])
|
||||
AC_CONFIG_HEADERS([src/config.h])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CXX
|
||||
AC_PROG_CC
|
||||
AM_PROG_AS
|
||||
AM_PROG_AR
|
||||
AC_PROG_RANLIB
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([stddef.h stdint.h])
|
||||
AC_CHECK_HEADERS([stddef.h stdint.h stdarg.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_CHECK_HEADER_STDBOOL
|
||||
|
||||
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 SYSTYPES_H
|
||||
#define SYSTYPES_H
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined __i386__ || __arm__
|
||||
typedef uint32_t physaddr_t;
|
||||
@@ -11,5 +9,3 @@ typedef uint64_t physaddr_t;
|
||||
#else
|
||||
typedef uint64_t physaddr_t;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
9
include/types/status.h
Normal file
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,4 +1,3 @@
|
||||
menuentry "Quark OS" {
|
||||
multiboot2 /apps/quark-kernel
|
||||
module2 /apps/test
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
noinst_PROGRAMS = quark-kernel
|
||||
quark_kernel_SOURCES = quarkkernel.cpp elf.cpp tty.cpp systeminfo.cpp util.cpp memorymap.cpp buddyallocator.cpp
|
||||
quark_kernel_SOURCES = kernel.c memorymap.c pageallocator.c priorityqueue.c stdio.c string.c
|
||||
quark_kernel_LDADD = -lgcc
|
||||
quark_kernel_CPPFLAGS = -ffreestanding -mgeneral-regs-only -O0 -Wall -fno-exceptions -fno-rtti -ggdb
|
||||
quark_kernel_CFLAGS = -I$(top_srcdir)/include -ffreestanding -mgeneral-regs-only -O0 -Wall -ggdb
|
||||
quark_kernel_LDFLAGS = -nostdlib
|
||||
|
||||
if x86
|
||||
quark_kernel_SOURCES += x86/pagetableentry.cpp \
|
||||
x86/mmap.cpp \
|
||||
x86/interrupts.cpp \
|
||||
x86/inthandlers.cpp \
|
||||
x86/interruptdescriptor.cpp \
|
||||
x86/idt.S \
|
||||
x86/entry.S \
|
||||
x86/pio.S \
|
||||
x86/multiboot2header.S
|
||||
quark_kernel_SOURCES += x86/mmgr.c \
|
||||
x86/putc.c \
|
||||
x86/multiboot2.c \
|
||||
x86/interrupts.c \
|
||||
x86/apic.c \
|
||||
x86/isr.c \
|
||||
x86/msr.c \
|
||||
x86/quark_x86.c \
|
||||
x86/entry.S
|
||||
quark_kernel_LDFLAGS += -T x86/linker.ld
|
||||
quark_kernel_DEPENDENCIES = x86/linker.ld
|
||||
endif
|
||||
|
||||
|
||||
102
src/allocator.cpp
Normal file
102
src/allocator.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "allocator.hpp"
|
||||
|
||||
#define AVAIL 0
|
||||
#define UNAVAIL -1
|
||||
|
||||
inline size_t ilog2(size_t n)
|
||||
{
|
||||
size_t m = n;
|
||||
size_t count = 0;
|
||||
bool isPowerOfTwo = true;
|
||||
while(m)
|
||||
{
|
||||
if((m & 1) == 1 && m > 1)
|
||||
{
|
||||
isPowerOfTwo = false;
|
||||
}
|
||||
count++;
|
||||
m >>= 1;
|
||||
}
|
||||
return count - (isPowerOfTwo ? 1 : 0);
|
||||
}
|
||||
|
||||
kernelns::Allocator::Allocator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
kernelns::Allocator::Allocator(void* base, size_t heapSize, size_t blockSize)
|
||||
{
|
||||
this->base = (char*) base;
|
||||
this->heapSize = heapSize;
|
||||
this->blockSize = blockSize;
|
||||
this->treeHeight = ilog2(heapSize / blockSize);
|
||||
size_t headerSize = (heapSize / blockSize) << 1;
|
||||
for(size_t i = 1; i < (heapSize / blockSize) * 2; i++)
|
||||
this->base[i] = UNAVAIL;
|
||||
for(size_t i = 0; i < heapSize / blockSize; i++)
|
||||
{
|
||||
if(blockSize * i >= headerSize)
|
||||
{
|
||||
size_t index = i + (1 << treeHeight);
|
||||
this->base[index] = AVAIL;
|
||||
for(; index > 1 && this->base[index ^ 1] == 0; index >>= 1)
|
||||
{
|
||||
this->base[index] = UNAVAIL;
|
||||
this->base[index ^ 1] = UNAVAIL;
|
||||
this->base[index >> 1] = AVAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->base[i + (1 << treeHeight)] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* kernelns::Allocator::allocate(size_t size)
|
||||
{
|
||||
size += blockSize - 1;
|
||||
size -= size % blockSize;
|
||||
size_t height = ilog2(size / blockSize);
|
||||
size_t index = findFreeBlock(height);
|
||||
if(index)
|
||||
{
|
||||
base[index] = height + 1;
|
||||
return (void*) ((size_t) base + (blockSize << height) * (index - (1 << (treeHeight - height))));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void kernelns::Allocator::free(void* location)
|
||||
{
|
||||
size_t offset = (size_t) location - (size_t) base;
|
||||
size_t index = (offset / blockSize) + (1 << treeHeight);
|
||||
for(; index > 0 && base[index] == UNAVAIL; index >>= 1);
|
||||
base[index] = AVAIL;
|
||||
for(; index > 1 && base[index ^ 1] == AVAIL; index >>= 1)
|
||||
{
|
||||
base[index] = UNAVAIL;
|
||||
base[index ^ 1] = UNAVAIL;
|
||||
base[index >> 1] = AVAIL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t kernelns::Allocator::findFreeBlock(size_t height)
|
||||
{
|
||||
if(height > treeHeight)
|
||||
return 0;
|
||||
for(size_t index = 1 << (treeHeight - height); index < 1 << (treeHeight - height + 1); index++)
|
||||
{
|
||||
if(base[index] == AVAIL)
|
||||
return index;
|
||||
}
|
||||
size_t index = findFreeBlock(height + 1);
|
||||
if(index)
|
||||
{
|
||||
base[index] = UNAVAIL;
|
||||
base[index << 1] = AVAIL;
|
||||
base[(index << 1) ^ 1] = AVAIL;
|
||||
}
|
||||
return index << 1;
|
||||
}
|
||||
42
src/allocator.hpp
Normal file
42
src/allocator.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef ALLOCATOR_H
|
||||
#define ALLOCATOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace kernelns
|
||||
{
|
||||
|
||||
class Allocator
|
||||
{
|
||||
public:
|
||||
|
||||
Allocator();
|
||||
|
||||
/**
|
||||
* @param base A pointer to the start of the heap.
|
||||
* @param heapSize The size of the heap, in bytes. Must be a power of two.
|
||||
* @param blockSize The smallest unit of allocation, in bytes. Must be a power of two less than or equal to heapSize.
|
||||
*/
|
||||
Allocator(void* base, size_t heapSize, size_t blockSize);
|
||||
|
||||
void* allocate(size_t size);
|
||||
|
||||
void free(void* location);
|
||||
|
||||
private:
|
||||
|
||||
size_t findFreeBlock(size_t height);
|
||||
|
||||
char* base;
|
||||
|
||||
size_t heapSize;
|
||||
|
||||
size_t blockSize;
|
||||
|
||||
size_t treeHeight;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,269 +0,0 @@
|
||||
#include "buddyallocator.hpp"
|
||||
#include "systypes.hpp"
|
||||
#include "memorymap.hpp"
|
||||
|
||||
#define roundUp(n, m) ((n % m == 0) ? n : (n + m - (n % m)))
|
||||
|
||||
uint32_t ilog2(uint32_t n, bool roundUp)
|
||||
{
|
||||
uint32_t m = n;
|
||||
uint32_t count = 0;
|
||||
bool isPowerOfTwo = true;
|
||||
while(m)
|
||||
{
|
||||
if((m & 1) == 1 && m > 1)
|
||||
{
|
||||
isPowerOfTwo = false;
|
||||
}
|
||||
count++;
|
||||
m >>= 1;
|
||||
}
|
||||
return count - (isPowerOfTwo ? 1 : (roundUp ? 0 : 1));
|
||||
}
|
||||
|
||||
kernel::BuddyAllocator::BuddyAllocator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
kernel::BuddyAllocator::BuddyAllocator(kernel::MemoryMap& memmap,
|
||||
char* bitmap, size_t blockCount,
|
||||
size_t treeHeight)
|
||||
{
|
||||
this->bitmap = bitmap;
|
||||
this->blockSize = 4096;
|
||||
this->blockCount = blockCount;
|
||||
this->treeHeight = treeHeight;
|
||||
for(size_t i = 0; i <= treeHeight; i++)
|
||||
{
|
||||
for(size_t j = 0; j < (blockCount >> i); j++)
|
||||
{
|
||||
reserveNode(i, j);
|
||||
}
|
||||
}
|
||||
physaddr_t location = 0x100000;
|
||||
for(size_t i = 0; i < memmap.size() && memmap[i].getSize() > 0; i++)
|
||||
{
|
||||
if(memmap[i].getType() != kernel::MemoryMap::AVAILABLE)
|
||||
continue;
|
||||
if(memmap[i].getLocation() > location)
|
||||
location = roundUp(memmap[i].getLocation(), 4096);
|
||||
while(memmap[i].contains(location, 4096))
|
||||
{
|
||||
freeNode(0, location / 4096);
|
||||
if(isFree(0, getBuddy(location / 4096)))
|
||||
merge(0, location / 4096);
|
||||
location += 4096;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kernel::BuddyAllocator::BuddyAllocator(char* bitmap, size_t blockSize,
|
||||
size_t blockCount, size_t treeHeight)
|
||||
{
|
||||
this->bitmap = bitmap;
|
||||
this->blockSize = blockSize;
|
||||
this->blockCount = blockCount;
|
||||
this->treeHeight = treeHeight;
|
||||
for(size_t i = 0; i <= treeHeight; i++)
|
||||
{
|
||||
for(size_t j = 0; j < (blockCount >> i); j++)
|
||||
{
|
||||
if(i < treeHeight)
|
||||
reserveNode(i, j);
|
||||
else
|
||||
freeNode(i, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
physaddr_t kernel::BuddyAllocator::allocate(size_t size)
|
||||
{
|
||||
size_t height = ilog2(roundUp(size, blockSize) / blockSize, true);
|
||||
if(height > treeHeight) // Requested block size is greater than maximum
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t index = findFreeBlock(height);
|
||||
if(index == INVALID) // Failed to find a big enough free block; out of memory
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
reserveNode(height, index);
|
||||
return nodeToAddress(height, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kernel::BuddyAllocator::free(physaddr_t location, size_t size)
|
||||
{
|
||||
size_t height = ilog2(roundUp(size, blockSize) / blockSize, true);
|
||||
if(height <= treeHeight)
|
||||
{
|
||||
size_t index = addressToNode(height, location);
|
||||
freeNode(height, index);
|
||||
if(isFree(height, getBuddy(index)))
|
||||
{
|
||||
merge(height, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::freeBlocks() const
|
||||
{
|
||||
size_t count = 0;
|
||||
for(size_t j = 0; j < blockCount; j++)
|
||||
{
|
||||
if(isFree(0, j))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::maxAllocationSize() const
|
||||
{
|
||||
for(size_t i = treeHeight; i >= 0; i--)
|
||||
{
|
||||
for(size_t j = 0; j < (blockCount >> i); j++)
|
||||
{
|
||||
if(isFree(i, j))
|
||||
{
|
||||
return 1 << i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::getBlockSize() const
|
||||
{
|
||||
return blockSize;
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::getMemorySize() const
|
||||
{
|
||||
return blockCount;
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::findFreeBlock(size_t height)
|
||||
{
|
||||
for(size_t i = 0; i < (blockCount >> height); i++)
|
||||
{
|
||||
if(isFree(height, i))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
if(height < treeHeight)
|
||||
{
|
||||
size_t parentIndex = findFreeBlock(height + 1);
|
||||
if(parentIndex != INVALID)
|
||||
{
|
||||
return split(height + 1, parentIndex);
|
||||
}
|
||||
}
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::split(size_t height, size_t index)
|
||||
{
|
||||
if(height > 0 && isFree(height, index))
|
||||
{
|
||||
reserveNode(height, index);
|
||||
freeNode(height - 1, getChild(index));
|
||||
freeNode(height - 1, getBuddy(getChild(index)));
|
||||
return getChild(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
return INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::merge(size_t height, size_t index)
|
||||
{
|
||||
if(isFree(height, index) && isFree(height, getBuddy(index)) && height < treeHeight)
|
||||
{
|
||||
reserveNode(height, index);
|
||||
reserveNode(height, getBuddy(index));
|
||||
freeNode(height + 1, getParent(index));
|
||||
if((height + 1) < treeHeight)
|
||||
{
|
||||
if(isFree(height + 1, getBuddy(getParent(index))))
|
||||
{
|
||||
return merge(height + 1, getParent(index));
|
||||
|
||||
}
|
||||
}
|
||||
return getParent(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
return INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::getBuddy(size_t index)
|
||||
{
|
||||
return index ^ 1;
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::getParent(size_t index)
|
||||
{
|
||||
return index / 2;
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::getChild(size_t index)
|
||||
{
|
||||
return index * 2;
|
||||
}
|
||||
|
||||
physaddr_t kernel::BuddyAllocator::nodeToAddress(size_t height, size_t index)
|
||||
const
|
||||
{
|
||||
return index * (blockSize << height);
|
||||
}
|
||||
|
||||
size_t kernel::BuddyAllocator::addressToNode(size_t height,
|
||||
physaddr_t location) const
|
||||
{
|
||||
return location / (blockSize << height);
|
||||
}
|
||||
|
||||
void kernel::BuddyAllocator::reserveNode(size_t height, size_t index)
|
||||
{
|
||||
size_t bit = (height == 0) ? 0
|
||||
: ((blockCount * 2) - (blockCount >> (height - 1)));
|
||||
bit += index;
|
||||
bitmap[bit / 8] |= 1 << (bit % 8);
|
||||
}
|
||||
|
||||
void kernel::BuddyAllocator::freeNode(size_t height, size_t index)
|
||||
{
|
||||
size_t bit = (height == 0) ? 0
|
||||
: ((blockCount * 2) - (blockCount >> (height - 1)));
|
||||
bit += index;
|
||||
bitmap[bit / 8] &= ~(1 << (bit % 8));
|
||||
}
|
||||
|
||||
bool kernel::BuddyAllocator::isFree(size_t height, size_t index) const
|
||||
{
|
||||
size_t bit = (height == 0) ? 0
|
||||
: ((blockCount * 2) - (blockCount >> (height - 1)));
|
||||
bit += index;
|
||||
char data = bitmap[bit / 8] & (1 << (bit % 8));
|
||||
if(data == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
#ifndef BUDDYALLOCATOR_H_
|
||||
#define BUDDYALLOCATOR_H_
|
||||
|
||||
#include "pageallocator.hpp"
|
||||
#include "memorymap.hpp"
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
class BuddyAllocator : public MemoryAllocator
|
||||
{
|
||||
public:
|
||||
|
||||
BuddyAllocator();
|
||||
|
||||
BuddyAllocator(MemoryMap& memmap, char* bitmap, size_t blockCount,
|
||||
size_t treeHeight);
|
||||
|
||||
BuddyAllocator(char* bitmap, size_t blockSize, size_t blockCount,
|
||||
size_t treeHeight);
|
||||
|
||||
/**
|
||||
* Allocate a block of memory containing at least 'size' bytes.
|
||||
* Rounds up to the nearest power of 2 times the size of a block.
|
||||
*/
|
||||
virtual physaddr_t allocate(size_t size);
|
||||
|
||||
/**
|
||||
* Free the region of memory starting at 'location' and containing
|
||||
* 'size' bytes.
|
||||
*/
|
||||
virtual void free(physaddr_t location, size_t size);
|
||||
|
||||
/**
|
||||
* @returns the total number of free blocks of memory.
|
||||
*/
|
||||
virtual size_t freeBlocks() const;
|
||||
|
||||
/**
|
||||
* @returns the size in blocks of the largest possible allocation that
|
||||
* will not fail due to lack of memory.
|
||||
*/
|
||||
virtual size_t maxAllocationSize() const;
|
||||
|
||||
/**
|
||||
* @returns the size in bytes of a single block.
|
||||
*/
|
||||
virtual size_t getBlockSize() const;
|
||||
|
||||
/**
|
||||
* @returns the total number of blocks managed by this memory
|
||||
* allocator.
|
||||
*/
|
||||
virtual size_t getMemorySize() const;
|
||||
|
||||
private:
|
||||
|
||||
static const size_t INVALID = (size_t) -1;
|
||||
|
||||
char* bitmap;
|
||||
|
||||
size_t blockSize;
|
||||
|
||||
size_t blockCount;
|
||||
|
||||
size_t treeHeight;
|
||||
|
||||
size_t findFreeBlock(size_t height);
|
||||
|
||||
size_t split(size_t height, size_t index);
|
||||
|
||||
size_t merge(size_t height, size_t index);
|
||||
|
||||
size_t getBuddy(size_t index);
|
||||
|
||||
size_t getParent(size_t index);
|
||||
|
||||
size_t getChild(size_t index);
|
||||
|
||||
physaddr_t nodeToAddress(size_t height, size_t index) const;
|
||||
|
||||
size_t addressToNode(size_t height, physaddr_t location) const;
|
||||
|
||||
void reserveNode(size_t height, size_t index);
|
||||
|
||||
void freeNode(size_t height, size_t index);
|
||||
|
||||
bool isFree(size_t height, size_t index) const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
39
src/elf.cpp
39
src/elf.cpp
@@ -1,39 +0,0 @@
|
||||
#include "elf.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
kernel::ELF::ELF(void* location)
|
||||
{
|
||||
this->location = location;
|
||||
}
|
||||
|
||||
void* kernel::ELF::entry()
|
||||
{
|
||||
Header* fileHeader = (Header*) location;
|
||||
return fileHeader->entry;
|
||||
}
|
||||
|
||||
int kernel::ELF::validate()
|
||||
{
|
||||
Header* fileHeader = (Header*) location;
|
||||
if(fileHeader->magic != 0x464c457f)
|
||||
return -1;
|
||||
else if((ISA) fileHeader->machine != HOST_ISA)
|
||||
return -1;
|
||||
else if((Endianness) fileHeader->endianness != Little)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kernel::ELF::load()
|
||||
{
|
||||
Header* fileHeader = (Header*) location;
|
||||
ProgramHeader* programHeader = (ProgramHeader*) ((size_t) location + fileHeader->phoffset);
|
||||
int count = (int) fileHeader->phcount;
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
if((SegmentType) programHeader->type != Load)
|
||||
continue;
|
||||
memcpy(programHeader->vaddr, location + programHeader->offset, programHeader->filesize);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
142
src/elf.hpp
142
src/elf.hpp
@@ -1,142 +0,0 @@
|
||||
#ifndef ELF_H
|
||||
#define ELF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "systypes.hpp"
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
class ELF
|
||||
{
|
||||
public:
|
||||
|
||||
enum Endianness
|
||||
{
|
||||
Little = 1,
|
||||
Big = 2
|
||||
};
|
||||
|
||||
enum ISA
|
||||
{
|
||||
NA = 0x00,
|
||||
x86 = 0x03,
|
||||
MIPS = 0x08,
|
||||
PPC = 0x14,
|
||||
PPC64 = 0x15,
|
||||
ARM = 0x28,
|
||||
x86_64 = 0x3E,
|
||||
aarch64 = 0xB7
|
||||
};
|
||||
|
||||
enum SegmentType
|
||||
{
|
||||
Unused = 0,
|
||||
Load = 1,
|
||||
Dynamic = 2
|
||||
};
|
||||
|
||||
struct Header
|
||||
{
|
||||
uint32_t magic;
|
||||
char size;
|
||||
char endianness;
|
||||
char version;
|
||||
char abi;
|
||||
char abiVersion;
|
||||
char reserved[7];
|
||||
uint16_t type;
|
||||
uint16_t machine;
|
||||
uint32_t _version;
|
||||
void* entry;
|
||||
#if defined __i386__ || defined __arm__
|
||||
uint32_t phoffset;
|
||||
uint32_t shoffset;
|
||||
#elif defined __x86_64__ || defined __aarch64__
|
||||
uint64_t phoffset;
|
||||
uint64_t shoffset;
|
||||
#endif
|
||||
uint32_t flags;
|
||||
uint16_t headerSize;
|
||||
uint16_t phsize;
|
||||
uint16_t phcount;
|
||||
uint16_t shsize;
|
||||
uint16_t shcount;
|
||||
uint16_t shstrndx;
|
||||
};
|
||||
|
||||
struct ProgramHeader
|
||||
{
|
||||
uint32_t type;
|
||||
#if defined __i386__ || defined __arm__
|
||||
uint32_t offset;
|
||||
void* vaddr;
|
||||
physaddr_t paddr;
|
||||
uint32_t filesize;
|
||||
uint32_t memsize;
|
||||
uint32_t flags;
|
||||
uint32_t align;
|
||||
#elif defined __x86_64__ || defined __aarch64__
|
||||
uint32_t flags;
|
||||
uint64_t offset;
|
||||
void* vaddr;
|
||||
physaddr_t paddr;
|
||||
uint64_t filesize;
|
||||
uint64_t memsize;
|
||||
uint64_t align;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct SectionHeader
|
||||
{
|
||||
uint32_t name;
|
||||
uint32_t type;
|
||||
#if defined __i386__ || defined __arm__
|
||||
uint32_t flags;
|
||||
void* addr;
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
uint32_t link;
|
||||
uint32_t info;
|
||||
uint32_t align;
|
||||
uint32_t entrysize;
|
||||
#elif defined __x86_64__ || defined __aarch64__
|
||||
uint64_t flags;
|
||||
void* addr;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
uint32_t link;
|
||||
uint32_t info;
|
||||
uint64_t align;
|
||||
uint64_t entrysize;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined __i386__
|
||||
static const ISA HOST_ISA = x86;
|
||||
#elif defined __x86_64__
|
||||
static const ISA HOST_ISA = x86_64;
|
||||
#elif defined __arm__
|
||||
static const ISA HOST_ISA = ARM;
|
||||
#elif defined __aarch64__
|
||||
static const ISA HOST_ISA = aarch64;
|
||||
#endif
|
||||
|
||||
ELF(void* location);
|
||||
|
||||
void* entry();
|
||||
|
||||
int validate();
|
||||
|
||||
int load();
|
||||
|
||||
private:
|
||||
|
||||
void* location;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef INTERRUPTS_H
|
||||
#define INTERRUPTS_H
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
class Interrupts
|
||||
{
|
||||
public:
|
||||
|
||||
Interrupts();
|
||||
|
||||
void enable();
|
||||
|
||||
void disable();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
11
src/kernel.c
Normal file
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,21 +0,0 @@
|
||||
#ifndef KERNELSTATE_H
|
||||
#define KERNELSTATE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "process.hpp"
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
class State
|
||||
{
|
||||
public:
|
||||
|
||||
static const size_t MAX_PROCESSES = 2048;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
136
src/memorymap.c
Normal file
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,38 +0,0 @@
|
||||
#include "memorymap.hpp"
|
||||
|
||||
kernel::MemoryMap::MemoryMap(kernel::MemoryMap::Region* map, size_t entries)
|
||||
{
|
||||
this->map = map;
|
||||
this->entries = entries;
|
||||
}
|
||||
|
||||
kernel::MemoryMap::Region& kernel::MemoryMap::operator[](size_t index)
|
||||
{
|
||||
return map[index];
|
||||
}
|
||||
|
||||
size_t kernel::MemoryMap::size()
|
||||
{
|
||||
return entries;
|
||||
}
|
||||
|
||||
physaddr_t kernel::MemoryMap::Region::getLocation()
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
size_t kernel::MemoryMap::Region::getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
kernel::MemoryMap::Type kernel::MemoryMap::Region::getType()
|
||||
{
|
||||
return (Type) type;
|
||||
}
|
||||
|
||||
bool kernel::MemoryMap::Region::contains(physaddr_t location, size_t size)
|
||||
{
|
||||
return (location >= this->location) &&
|
||||
(location + size <= this->location + this->size);
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#ifndef MEMORYMAP_H
|
||||
#define MEMORYMAP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "systypes.hpp"
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
class MemoryMap
|
||||
{
|
||||
public:
|
||||
|
||||
enum Type
|
||||
{
|
||||
AVAILABLE = 1,
|
||||
ACPI = 3,
|
||||
DEFECTIVE = 5
|
||||
};
|
||||
|
||||
class Region
|
||||
{
|
||||
public:
|
||||
|
||||
physaddr_t getLocation();
|
||||
|
||||
size_t getSize();
|
||||
|
||||
Type getType();
|
||||
|
||||
bool contains(physaddr_t location, size_t size);
|
||||
|
||||
private:
|
||||
|
||||
physaddr_t location;
|
||||
|
||||
size_t size;
|
||||
|
||||
uint32_t type;
|
||||
|
||||
};
|
||||
|
||||
MemoryMap(Region* map, size_t entries);
|
||||
|
||||
Region& operator[](size_t index);
|
||||
|
||||
size_t size();
|
||||
|
||||
private:
|
||||
|
||||
Region* map;
|
||||
|
||||
size_t entries;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
27
src/mmap.hpp
27
src/mmap.hpp
@@ -1,27 +0,0 @@
|
||||
#ifndef MMAP_H
|
||||
#define MMAP_H
|
||||
|
||||
#include "pageallocator.hpp"
|
||||
|
||||
#define MMAP_RW 0x01
|
||||
#define MMAP_EXEC 0x02
|
||||
#define MMAP_SHARED 0x04
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
int mmap(MemoryAllocator& allocator, void* start, size_t length, int flags);
|
||||
|
||||
int munmap(MemoryAllocator& allocator, void* start, size_t length);
|
||||
|
||||
bool isMapped(void* addr);
|
||||
|
||||
physaddr_t getPhysicalAddress(void* addr);
|
||||
|
||||
int createAddressSpace(void* table);
|
||||
|
||||
int loadAddressSpace(physaddr_t table);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,7 +0,0 @@
|
||||
#ifndef MMGR_H
|
||||
#define MMGR_H
|
||||
|
||||
#include "mmap.hpp"
|
||||
#include "buddyallocator.hpp"
|
||||
|
||||
#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,55 +0,0 @@
|
||||
#ifndef __MEMORYALLOCATOR_H_
|
||||
#define __MEMORYALLOCATOR_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include "systypes.hpp"
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
/**
|
||||
* Interface for a dymanic memory allocator.
|
||||
*/
|
||||
class MemoryAllocator
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Allocate a block of memory containing 'size' bytes. May round up
|
||||
* depending on the implementation.
|
||||
*/
|
||||
virtual physaddr_t allocate(size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Free the region of memory starting at 'location' and containing
|
||||
* 'size' bytes.
|
||||
*/
|
||||
virtual void free(physaddr_t location, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* @returns the total number of free blocks of memory.
|
||||
*/
|
||||
virtual size_t freeBlocks() const = 0;
|
||||
|
||||
/**
|
||||
* @returns the size in blocks of the largest possible allocation that
|
||||
* will not fail due to lack of memory.
|
||||
*/
|
||||
virtual size_t maxAllocationSize() const = 0;
|
||||
|
||||
/**
|
||||
* @returns the size in bytes of a single block.
|
||||
*/
|
||||
virtual size_t getBlockSize() const = 0;
|
||||
|
||||
/**
|
||||
* @returns the total number of blocks managed by this memory
|
||||
* allocator.
|
||||
*/
|
||||
virtual size_t getMemorySize() const = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
67
src/priorityqueue.c
Normal file
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,36 +0,0 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "systypes.hpp"
|
||||
#include "systeminfo.hpp"
|
||||
#include "mmgr.hpp"
|
||||
#include "x86/pio.hpp"
|
||||
#include "tty.hpp"
|
||||
#include "util.hpp"
|
||||
#include "config.h"
|
||||
|
||||
using namespace kernel;
|
||||
|
||||
extern SystemInfo system_info;
|
||||
extern MemoryMap::Region memory_map;
|
||||
|
||||
void main(char* cmdline)
|
||||
{
|
||||
TTY tty((char*) 0xFF8B8000);
|
||||
tty << PACKAGE_STRING << "\n\n";
|
||||
tty << "Low memory: \t" << (int) system_info.getLowMemory() << " KiB\n";
|
||||
tty << "High memory:\t" << (int) system_info.getHighMemory() << " KiB\n";
|
||||
tty << "Type\t\tLocation\t\tSize\n";
|
||||
MemoryMap memmap(&memory_map, 16);
|
||||
for(size_t i = 0; i < memmap.size() && memmap[i].getSize() > 0; i++)
|
||||
{
|
||||
tty << (int) memmap[i].getType() << "\t\t\t";
|
||||
tty << (void*) memmap[i].getLocation() << "\t\t";
|
||||
tty << (int) memmap[i].getSize() << "\n";
|
||||
}
|
||||
BuddyAllocator alloc(memmap, (char*) 0xFF800000, system_info.getHighMemory() / 4 + 256, 6);
|
||||
mmap(alloc, (void*) 0, 4096, MMAP_RW);
|
||||
outb(0xa1, 0xff);
|
||||
outb(0x21, 0xff);
|
||||
tty << "Nothing left to do. Hanging.\n";
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#include "scheduler.hpp"
|
||||
|
||||
kernel::ProcessQueue::ProcessQueue(Process** array)
|
||||
{
|
||||
m_array = array;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
kernel::Process* kernel::ProcessQueue::extractMin()
|
||||
{
|
||||
if(m_size == 0)
|
||||
return NULL;
|
||||
m_size--;
|
||||
Process* p = m_array[0];
|
||||
m_array[0] = m_array[m_size];
|
||||
heapify(0);
|
||||
}
|
||||
|
||||
void kernel::ProcessQueue::insert(Process* n)
|
||||
{
|
||||
size_t i = m_size;
|
||||
m_size++;
|
||||
for(; i > 0 && m_array[(i - 1) / 2]->priority > n->priority; i = (i - 1) / 2)
|
||||
{
|
||||
m_array[i] = m_array[(i - 1) / 2];
|
||||
}
|
||||
m_array[i] = n;
|
||||
}
|
||||
|
||||
void kernel::ProcessQueue::remove(Process* n)
|
||||
{
|
||||
for(size_t i = 0; i < m_size; i++)
|
||||
{
|
||||
if(m_array[i] == n)
|
||||
{
|
||||
m_size--;
|
||||
m_array[i] = m_array[m_size];
|
||||
heapify(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void kernel::ProcessQueue::heapify(size_t i)
|
||||
{
|
||||
if(i * 2 + 1 >= m_size)
|
||||
return;
|
||||
if (m_array[i]->priority >= m_array[i * 2 + 1]->priority && m_array[i * 2 + 1]->priority <= m_array[i * 2 + 2]->priority)
|
||||
{
|
||||
Process* buffer = m_array[i];
|
||||
m_array[i] = m_array[i * 2 + 1];
|
||||
m_array[i * 2 + 1] = buffer;
|
||||
heapify(i * 2 + 1);
|
||||
}
|
||||
else if (m_array[i]->priority >= m_array[i * 2 + 2]->priority && m_array[i * 2 + 2]->priority <= m_array[i * 2 + 1]->priority)
|
||||
{
|
||||
Process* buffer = m_array[i];
|
||||
m_array[i] = m_array[i * 2 + 2];
|
||||
m_array[i * 2 + 2] = buffer;
|
||||
heapify(i * 2 + 2);
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#ifndef SCHEDULER_H
|
||||
#define SCHEDULER_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
class Process
|
||||
{
|
||||
public:
|
||||
|
||||
Process();
|
||||
|
||||
size_t priority;
|
||||
|
||||
void* stack;
|
||||
|
||||
};
|
||||
|
||||
class ProcessQueue
|
||||
{
|
||||
public:
|
||||
|
||||
ProcessQueue(Process** array);
|
||||
|
||||
Process* extractMin();
|
||||
|
||||
void insert(Process* n);
|
||||
|
||||
void remove(Process* n);
|
||||
|
||||
private:
|
||||
|
||||
void heapify(size_t index);
|
||||
|
||||
Process** m_array;
|
||||
|
||||
size_t m_size;
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
100
src/stdio.c
Normal file
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,16 +0,0 @@
|
||||
#include "systeminfo.hpp"
|
||||
|
||||
size_t kernel::SystemInfo::getLowMemory()
|
||||
{
|
||||
return lowMemory;
|
||||
}
|
||||
|
||||
size_t kernel::SystemInfo::getHighMemory()
|
||||
{
|
||||
return highMemory;
|
||||
}
|
||||
|
||||
physaddr_t kernel::SystemInfo::getKernelBase()
|
||||
{
|
||||
return kernelBase;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef SYSTEMINFO_H
|
||||
#define SYSTEMINFO_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "systypes.hpp"
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
class SystemInfo
|
||||
{
|
||||
public:
|
||||
|
||||
size_t getLowMemory();
|
||||
|
||||
size_t getHighMemory();
|
||||
|
||||
physaddr_t getKernelBase();
|
||||
|
||||
private:
|
||||
|
||||
size_t lowMemory;
|
||||
|
||||
size_t highMemory;
|
||||
|
||||
physaddr_t kernelBase;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
125
src/tty.cpp
125
src/tty.cpp
@@ -1,125 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include "tty.hpp"
|
||||
|
||||
kernel::TTY::TTY(char* vga)
|
||||
{
|
||||
this->vga = vga;
|
||||
this->cursor = 0;
|
||||
this->width = 0;
|
||||
this->base = 10;
|
||||
}
|
||||
|
||||
kernel::TTY& kernel::TTY::operator<<(kernel::TTY::Format fmt)
|
||||
{
|
||||
switch(fmt)
|
||||
{
|
||||
case Binary:
|
||||
base = 2;
|
||||
break;
|
||||
case Decimal:
|
||||
base = 10;
|
||||
break;
|
||||
case Hex:
|
||||
base = 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
kernel::TTY& kernel::TTY::operator<<(const char* str)
|
||||
{
|
||||
return printString(str);
|
||||
}
|
||||
|
||||
kernel::TTY& kernel::TTY::operator<<(unsigned int n)
|
||||
{
|
||||
return printNumber(n, base, width);
|
||||
}
|
||||
|
||||
kernel::TTY& kernel::TTY::operator<<(int n)
|
||||
{
|
||||
return printNumber((unsigned int) n, base, width);
|
||||
}
|
||||
|
||||
kernel::TTY& kernel::TTY::operator<<(void* n)
|
||||
{
|
||||
return printNumber((unsigned int) n, 16, 8);
|
||||
}
|
||||
|
||||
kernel::TTY& kernel::TTY::operator<<(char c)
|
||||
{
|
||||
return putChar(c);
|
||||
}
|
||||
|
||||
void kernel::TTY::setWidth(size_t width)
|
||||
{
|
||||
this->width = width;
|
||||
}
|
||||
|
||||
size_t kernel::TTY::getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
void kernel::TTY::clear()
|
||||
{
|
||||
for(int i = 0; i < 80*25; i++)
|
||||
{
|
||||
vga[i * 2] = ' ';
|
||||
}
|
||||
cursor = 0;
|
||||
}
|
||||
|
||||
kernel::TTY& kernel::TTY::printNumber(unsigned int n, size_t base,
|
||||
size_t width)
|
||||
{
|
||||
const char* digits = "0123456789ABCDEF";
|
||||
char str[33];
|
||||
size_t i = 1;
|
||||
do
|
||||
{
|
||||
str[i] = digits[n % base];
|
||||
n /= base;
|
||||
i++;
|
||||
} while(n > 0);
|
||||
while(i <= width)
|
||||
{
|
||||
str[i] = '0';
|
||||
i++;
|
||||
}
|
||||
str[0] = '\0';
|
||||
for(char* s = str + (i - 1); *s; s--)
|
||||
{
|
||||
putChar(*s);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
kernel::TTY& kernel::TTY::printString(const char* str)
|
||||
{
|
||||
while(*str)
|
||||
{
|
||||
putChar(*str);
|
||||
str++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
kernel::TTY& kernel::TTY::putChar(char c)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case '\n':
|
||||
cursor = (cursor + 80) - (cursor % 80);
|
||||
break;
|
||||
case '\t':
|
||||
cursor = (cursor + 4) - (cursor % 4);
|
||||
break;
|
||||
case '\r':
|
||||
cursor -= cursor % 160;
|
||||
break;
|
||||
default:
|
||||
vga[cursor * 2] = c;
|
||||
cursor++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
60
src/tty.hpp
60
src/tty.hpp
@@ -1,60 +0,0 @@
|
||||
#ifndef TTY_H_
|
||||
#define TTY_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
class TTY
|
||||
{
|
||||
public:
|
||||
|
||||
enum Format
|
||||
{
|
||||
Binary,
|
||||
Decimal,
|
||||
Hex
|
||||
};
|
||||
|
||||
TTY(char* vga);
|
||||
|
||||
TTY& operator<<(Format fmt);
|
||||
|
||||
TTY& operator<<(const char* str);
|
||||
|
||||
TTY& operator<<(unsigned int n);
|
||||
|
||||
TTY& operator<<(int n);
|
||||
|
||||
TTY& operator<<(void* n);
|
||||
|
||||
TTY& operator<<(char c);
|
||||
|
||||
void setWidth(size_t width);
|
||||
|
||||
size_t getWidth();
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
|
||||
TTY& printNumber(unsigned int n, size_t base, size_t width);
|
||||
|
||||
TTY& printString(const char* str);
|
||||
|
||||
TTY& putChar(char c);
|
||||
|
||||
char* vga;
|
||||
|
||||
int cursor;
|
||||
|
||||
size_t width;
|
||||
|
||||
size_t base;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
81
src/util.cpp
81
src/util.cpp
@@ -1,81 +0,0 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util.hpp"
|
||||
|
||||
void* memcpy(void* destination, const void* source, size_t num)
|
||||
{
|
||||
if(num > 0)
|
||||
{
|
||||
const uint8_t* src = (const uint8_t*) source;
|
||||
uint8_t* dest = (uint8_t*) destination;
|
||||
for(size_t i = 0; i < num; i++)
|
||||
{
|
||||
dest[i] = src[i];
|
||||
}
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
/*
|
||||
* There are four distinct cases here:
|
||||
* 1. destination and source blocks do not overlap
|
||||
* 2. destination and source are the same
|
||||
* 3. destination and source do overlap; destination starts before source
|
||||
* 4. destination and source do overlap; destination starts after source
|
||||
*
|
||||
* Memcpy results in expected behavior in all cases except for case 4. In that
|
||||
* case, copying must be done backwards to avoid reading from bytes that have
|
||||
* already been overwritten.
|
||||
*/
|
||||
void* memmove(void* destination, const void* source, size_t num)
|
||||
{
|
||||
if(num > 0)
|
||||
{
|
||||
if(((size_t) destination) < ((size_t) source) || ((size_t) destination) >= (((size_t) source)) + num)
|
||||
{
|
||||
return memcpy(destination, source, num);
|
||||
}
|
||||
else if(destination != source)
|
||||
{
|
||||
size_t i = num - 1;
|
||||
const uint8_t* src = (const uint8_t*) source;
|
||||
uint8_t* dest = (uint8_t*) destination;
|
||||
do
|
||||
{
|
||||
dest[i] = src[i];
|
||||
i--;
|
||||
} while(i != 0);
|
||||
}
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
|
||||
int memcmp(const void* ptr1, const void* ptr2, size_t num)
|
||||
{
|
||||
const uint8_t* a = (const uint8_t*) ptr1;
|
||||
const uint8_t* b = (const uint8_t*) ptr2;
|
||||
for(size_t i = 0; i < num; i++)
|
||||
{
|
||||
if(a[i] < b[i])
|
||||
return -1;
|
||||
else if(a[i] > b[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* memset (void* ptr, int value, size_t num)
|
||||
{
|
||||
uint8_t* dest = (uint8_t*) ptr;
|
||||
uint8_t v = (uint8_t) value;
|
||||
for(size_t i = 0; i < num; i++)
|
||||
{
|
||||
dest[i] = v;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void __cxa_pure_virtual()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
16
src/util.hpp
16
src/util.hpp
@@ -1,16 +0,0 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
extern "C" void __cxa_pure_virtual();
|
||||
|
||||
extern "C" void* memcpy(void* destination, const void* source, size_t num);
|
||||
|
||||
extern "C" void* memmove(void* destination, const void* source, size_t num);
|
||||
|
||||
extern "C" int memcmp(const void* ptr1, const void* ptr2, size_t num);
|
||||
|
||||
extern "C" void* memset(void* ptr, int value, size_t num);
|
||||
|
||||
#endif
|
||||
35
src/x86/apic.c
Normal file
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);
|
||||
297
src/x86/entry.S
297
src/x86/entry.S
@@ -1,5 +1,98 @@
|
||||
.section .multiboot
|
||||
.include "x86/multiboot2header.S"
|
||||
|
||||
/*
|
||||
* Define constants for the multiboot header. See Multiboot 2 Specifications for details.
|
||||
*/
|
||||
.set align, 1<<0
|
||||
.set meminfo, 1<<1
|
||||
.set magic, 0xE85250D6
|
||||
.set arch, 0
|
||||
.set headerLength, _multibootHeaderEnd - _multibootHeaderStart
|
||||
.set checksum, -(magic + arch + headerLength)
|
||||
|
||||
.set tagNotOptional, 0
|
||||
|
||||
.set tagInfoRequestType, 1
|
||||
.set tagInfoRequestSize, _multibootInfoTagEnd - _multibootInfoTagStart
|
||||
.set requestBootCommand, 1
|
||||
.set requestBootLoaderName, 2
|
||||
.set requestBootModules, 3
|
||||
.set requestMemoryInfo, 4
|
||||
.set requestBootDevice, 5
|
||||
.set requestMemoryMap, 6
|
||||
|
||||
.set tagAddressType, 2
|
||||
.set tagAddressSize, 24
|
||||
.set tagAddressHeaderLocation, LOAD_START
|
||||
.set tagAddressLoadStart, LOAD_START
|
||||
.set tagAddressLoadEnd, LOAD_END
|
||||
.set tagAddressBSSEnd, BSS_END
|
||||
|
||||
.set tagEntryType, 3
|
||||
.set tagEntrySize, 12
|
||||
.set tagEntryAddress, _start - (0xFF900000 - 0x100000)
|
||||
|
||||
.set tagModuleAlignType, 6
|
||||
.set tagModuleAlignSize, 8
|
||||
|
||||
/*
|
||||
* Each multiboot tag must be 8-byte aligned, or GRUB will not be able to read the header.
|
||||
*/
|
||||
.align 8
|
||||
_multibootHeaderStart:
|
||||
|
||||
.long magic
|
||||
.long arch
|
||||
.long headerLength
|
||||
.long checksum
|
||||
|
||||
.align 8
|
||||
|
||||
_multibootInfoTagStart:
|
||||
.short tagInfoRequestType
|
||||
.short tagNotOptional
|
||||
.long tagInfoRequestSize
|
||||
.long requestBootCommand
|
||||
.long requestBootLoaderName
|
||||
.long requestBootModules
|
||||
.long requestMemoryInfo
|
||||
.long requestBootDevice
|
||||
.long requestMemoryMap
|
||||
_multibootInfoTagEnd:
|
||||
|
||||
.align 8
|
||||
|
||||
.short tagAddressType
|
||||
.short tagNotOptional
|
||||
.long tagAddressSize
|
||||
.long tagAddressHeaderLocation
|
||||
.long tagAddressLoadStart
|
||||
.long tagAddressLoadEnd
|
||||
.long tagAddressBSSEnd
|
||||
|
||||
.align 8
|
||||
|
||||
.short tagEntryType
|
||||
.short tagNotOptional
|
||||
.long tagEntrySize
|
||||
.long tagEntryAddress
|
||||
|
||||
.align 8
|
||||
|
||||
.short tagModuleAlignType
|
||||
.short tagNotOptional
|
||||
.long tagModuleAlignSize
|
||||
|
||||
.align 8
|
||||
|
||||
/*
|
||||
* Terminate list of multiboot header tags.
|
||||
* Ending tag has type = 0, flags = 0, size = 8
|
||||
*/
|
||||
.long 0
|
||||
.long 8
|
||||
|
||||
_multibootHeaderEnd:
|
||||
|
||||
.section .rodata
|
||||
|
||||
@@ -31,7 +124,7 @@ _tempPgDir:
|
||||
_tempIdentityMap:
|
||||
.skip 4096
|
||||
_tempPgTable:
|
||||
.skip 8192
|
||||
.skip 4096
|
||||
|
||||
_bootCmdLine:
|
||||
.skip 64
|
||||
@@ -50,181 +143,57 @@ memory_map:
|
||||
.global _start
|
||||
.type _start, @function
|
||||
_start:
|
||||
|
||||
cli
|
||||
|
||||
# This platform reqires a Multiboot2 bootloader.
|
||||
cmp $0x36d76289, %eax
|
||||
jne _err
|
||||
jne .err
|
||||
|
||||
movb $64, 0xB8000
|
||||
# Initialize stack in physical address space
|
||||
mov $stackTop, %esp
|
||||
sub $BASE_DIFF, %esp
|
||||
|
||||
mov $system_info, %edi
|
||||
sub $BASE_DIFF, %edi
|
||||
add $8, %ebx
|
||||
|
||||
switch:
|
||||
mov (%ebx), %eax
|
||||
cmp $0, %eax
|
||||
je s_end
|
||||
cmp $1, %eax
|
||||
je tag_1
|
||||
cmp $3, %eax
|
||||
je tag_3
|
||||
cmp $4, %eax
|
||||
je tag_4
|
||||
cmp $6, %eax
|
||||
je tag_6
|
||||
cmp $21, %eax
|
||||
je tag_21
|
||||
jmp def
|
||||
|
||||
# Boot command line
|
||||
tag_1:
|
||||
mov 4(%ebx), %ecx
|
||||
sub $8, %ecx
|
||||
mov %ebx, %esi
|
||||
add $8, %esi
|
||||
mov $_bootCmdLine, %edi
|
||||
sub $BASE_DIFF, %edi
|
||||
rep movsb
|
||||
mov $system_info, %edi
|
||||
sub $BASE_DIFF, %edi
|
||||
jmp def
|
||||
|
||||
tag_3:
|
||||
mov 8(%ebx), %esi
|
||||
mov (%esi), %eax
|
||||
mov %al, (0xB8004)
|
||||
mov %ah, (0xB8006)
|
||||
shr $16, %eax
|
||||
mov %al, (0xB8008)
|
||||
mov %ah, (0xB800a)
|
||||
jmp def
|
||||
|
||||
# Basic memory info
|
||||
tag_4:
|
||||
mov 8(%ebx), %eax
|
||||
mov %eax, (%edi)
|
||||
mov 12(%ebx), %eax
|
||||
mov %eax, 4(%edi)
|
||||
jmp def
|
||||
|
||||
# Memory map
|
||||
tag_6:
|
||||
mov $memory_map, %esi
|
||||
sub $BASE_DIFF, %esi # set esi to point to the table in the kernel image
|
||||
mov 4(%ebx), %ecx
|
||||
sub $16, %ecx # set ecx to store the size of the table provided by the bootloader
|
||||
mov 8(%ebx), %edx # set edx to store the size of each table entry
|
||||
add $16, %ebx # move ebx up to the first entry
|
||||
1: mov (%ebx), %eax
|
||||
mov %eax, (%esi) # save the address of that region in memory
|
||||
mov 8(%ebx), %eax
|
||||
mov %eax, 4(%esi) # save the size of that region in memory
|
||||
mov 16(%ebx), %eax
|
||||
mov %eax, 8(%esi) # save the type of memory in that region
|
||||
add $12, %esi # move esi to the next entry in the kernel's array
|
||||
add %edx, %ebx # move ebx to the next entry in the bootloader's array
|
||||
sub %edx, %ecx # subtract the size of an entry from ecx.
|
||||
jnz 1b # loop if there are entries left
|
||||
mov $0, %eax
|
||||
mov %eax, (%esi)
|
||||
mov %eax, 4(%esi)
|
||||
mov %eax, 8(%esi)
|
||||
jmp switch
|
||||
|
||||
# Program image location
|
||||
tag_21:
|
||||
mov 8(%ebx), %eax
|
||||
mov %eax, 8(%edi)
|
||||
jmp def
|
||||
|
||||
def:
|
||||
mov 4(%ebx), %eax
|
||||
add $7, %eax
|
||||
and $0xFFFFFFF8, %eax
|
||||
add %eax, %ebx
|
||||
jmp switch
|
||||
s_end:
|
||||
|
||||
movb $64, 0xB8002
|
||||
|
||||
mov $0, %ecx
|
||||
1:
|
||||
# Generate a page table entry pointing to a page in the kernel binary
|
||||
mov %ecx, %eax
|
||||
mov $4096, %edx
|
||||
mul %edx
|
||||
or $3, %eax
|
||||
|
||||
# Load the address of the temporary page table and translate it to a physical address
|
||||
mov $_tempPgTable, %edi
|
||||
sub $BASE_DIFF, %edi
|
||||
|
||||
# Save the PTE into an entry in the temporary page table
|
||||
mov %eax, (%edi, %ecx, 4)
|
||||
|
||||
# Load the address of the identity map and translate it to a physical address
|
||||
mov $_tempIdentityMap, %edi
|
||||
sub $BASE_DIFF, %edi
|
||||
|
||||
# Save the PTE into an entry in the identity map
|
||||
mov %eax, (%edi, %ecx, 4)
|
||||
|
||||
# Increment count and loop
|
||||
inc %ecx
|
||||
mov $IMAGE_SIZE, %edx
|
||||
add $256, %edx
|
||||
cmp %edx, %ecx
|
||||
jne 1b
|
||||
|
||||
# Load the physical address of the identity map, and generate a PDE
|
||||
# Push physical address of identity map
|
||||
mov $_tempIdentityMap, %eax
|
||||
sub $BASE_DIFF, %eax
|
||||
or $3, %eax
|
||||
push %eax
|
||||
|
||||
# Load the physical address of the page directory
|
||||
mov $_tempPgDir, %edi
|
||||
sub $BASE_DIFF, %edi
|
||||
|
||||
# Save the PDE to the first element in the page directory
|
||||
mov %eax, (%edi)
|
||||
|
||||
# Load the physical address of the temporary page table, and generate a PDE
|
||||
# Push physical address of page table
|
||||
mov $_tempPgTable, %eax
|
||||
sub $BASE_DIFF, %eax
|
||||
or $3, %eax
|
||||
push %eax
|
||||
|
||||
# Save the PDE to the entry corresponding to 0xC0000000
|
||||
mov %eax, 4088(%edi)
|
||||
# Push physical address of page directory
|
||||
mov $_tempPgDir, %eax
|
||||
sub $BASE_DIFF, %eax
|
||||
push %eax
|
||||
|
||||
# Set the last entry in the page directory to point to the page directory itself
|
||||
mov %edi, %eax
|
||||
or $3, %eax
|
||||
mov %eax, 4092(%edi)
|
||||
# Load physical address of startPaging()
|
||||
mov $startPaging, %eax
|
||||
sub $BASE_DIFF, %eax
|
||||
|
||||
# Load the physical address of the page directory into CR3
|
||||
mov $_tempPgDir, %edi
|
||||
sub $BASE_DIFF, %edi
|
||||
mov %edi, %cr3
|
||||
|
||||
# Enable paging
|
||||
mov %cr0, %eax
|
||||
or $0x80010000, %eax
|
||||
mov %eax, %cr0
|
||||
# Initialize paging
|
||||
call *%eax
|
||||
|
||||
# Jump into mapped kernel binary
|
||||
lea 2f, %eax
|
||||
lea 1f, %eax
|
||||
jmp *%eax
|
||||
2:
|
||||
1:
|
||||
# Delete PDE corresponding to identity map. We shouldn't need it anymore.
|
||||
movl $0, (_tempIdentityMap)
|
||||
|
||||
# Reload page tables
|
||||
# Flush TLB
|
||||
mov %cr3, %eax
|
||||
mov %eax, %cr3
|
||||
|
||||
# Initialize stack
|
||||
# Initialize stack in virtual memory
|
||||
mov $stackTop, %esp
|
||||
|
||||
# Load GPT
|
||||
lgdt gdt_info
|
||||
|
||||
# Load segment registers
|
||||
jmp $8, $.ldcs
|
||||
.ldcs:
|
||||
mov $16, %ax
|
||||
@@ -234,15 +203,21 @@ s_end:
|
||||
mov %ax, %fs
|
||||
mov %ax, %ss
|
||||
|
||||
mov $_bootCmdLine, %eax
|
||||
push %eax
|
||||
# Change EBX to point to the virtual address of the multiboot info
|
||||
# If the new pointer is out-of-bounds, error
|
||||
add $0xFF800000, %ebx
|
||||
cmp $0xFF800000, %ebx
|
||||
jl .err
|
||||
cmp $0xFFC00000, %ebx
|
||||
jge .err
|
||||
|
||||
# Call main function
|
||||
call main
|
||||
# Call initialize(void* multibootInfo)
|
||||
push %ebx
|
||||
call initialize
|
||||
|
||||
_err:
|
||||
.err:
|
||||
cli
|
||||
3: hlt
|
||||
jmp 3b
|
||||
2: hlt
|
||||
jmp 2b
|
||||
|
||||
.size _start, . - _start
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
.section .bss
|
||||
|
||||
.align 8
|
||||
.global idt
|
||||
idt:
|
||||
.skip 8 * 256
|
||||
idt_end:
|
||||
|
||||
.section .rodata
|
||||
|
||||
.idt_info:
|
||||
.short idt_end - idt - 1
|
||||
.long idt
|
||||
|
||||
.section .text
|
||||
|
||||
.global _lidt
|
||||
.type _lidt, @function
|
||||
_lidt:
|
||||
|
||||
ret
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef IDT_H
|
||||
#define IDT_H
|
||||
|
||||
#include "interruptdescriptor.hpp"
|
||||
|
||||
extern kernel::InterruptDescriptor idt[256];
|
||||
|
||||
extern "C" void _lidt();
|
||||
|
||||
#endif
|
||||
@@ -1,63 +0,0 @@
|
||||
#include "interruptdescriptor.hpp"
|
||||
|
||||
kernel::InterruptDescriptor::InterruptDescriptor()
|
||||
{
|
||||
this->m_offset1 = 0;
|
||||
this->m_selector = 0;
|
||||
this->m_zero = 0;
|
||||
this->m_type = 0;
|
||||
this->m_storage = 0;
|
||||
this->m_dpl = 0;
|
||||
this->m_present = 0;
|
||||
this->m_offset2 = 0;
|
||||
}
|
||||
|
||||
kernel::InterruptDescriptor::InterruptDescriptor(void* handler, Type type, unsigned int dpl)
|
||||
{
|
||||
uint32_t offset = (uint32_t) handler;
|
||||
this->m_offset1 = (uint16_t) offset;
|
||||
this->m_selector = 8;
|
||||
this->m_zero = 0;
|
||||
this->m_type = (uint16_t) type;
|
||||
this->m_storage = 0;
|
||||
this->m_dpl = dpl;
|
||||
this->m_present = 1;
|
||||
this->m_offset2 = offset >> 16;
|
||||
}
|
||||
|
||||
bool kernel::InterruptDescriptor::present()
|
||||
{
|
||||
return m_present == 1;
|
||||
}
|
||||
void kernel::InterruptDescriptor::present(bool present)
|
||||
{
|
||||
m_present = present ? 1 : 0;
|
||||
}
|
||||
|
||||
kernel::InterruptDescriptor::Type kernel::InterruptDescriptor::type()
|
||||
{
|
||||
return (Type) m_type;
|
||||
}
|
||||
|
||||
void kernel::InterruptDescriptor::type(kernel::InterruptDescriptor::Type type)
|
||||
{
|
||||
m_type = (unsigned int) type;
|
||||
}
|
||||
|
||||
unsigned int kernel::InterruptDescriptor::dpl()
|
||||
{
|
||||
return m_dpl;
|
||||
}
|
||||
|
||||
void kernel::InterruptDescriptor::dpl(unsigned int dpl)
|
||||
{
|
||||
m_dpl = dpl;
|
||||
}
|
||||
|
||||
void* kernel::InterruptDescriptor::operator=(void* rhs)
|
||||
{
|
||||
uint32_t offset = (uint32_t) rhs;
|
||||
m_offset1 = (uint16_t) offset;
|
||||
m_offset2 = (offset >> 16);
|
||||
return rhs;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
#ifndef INTERRUPTDESCRIPTOR_H
|
||||
#define INTERRUPTDESCRIPTOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace kernel
|
||||
{
|
||||
|
||||
class InterruptDescriptor
|
||||
{
|
||||
public:
|
||||
|
||||
enum Type
|
||||
{
|
||||
TASK32 = 5,
|
||||
TRAP32 = 15,
|
||||
INT32 = 14,
|
||||
TRAP16 = 7,
|
||||
INT16 = 6
|
||||
};
|
||||
|
||||
InterruptDescriptor();
|
||||
|
||||
InterruptDescriptor(void* handler, Type type, unsigned int dpl);
|
||||
|
||||
bool present();
|
||||
|
||||
void present(bool present);
|
||||
|
||||
Type type();
|
||||
|
||||
void type(Type type);
|
||||
|
||||
unsigned int dpl();
|
||||
|
||||
void dpl(unsigned int dpl);
|
||||
|
||||
void* operator=(void* rhs);
|
||||
|
||||
private:
|
||||
|
||||
uint16_t m_offset1;
|
||||
uint16_t m_selector;
|
||||
uint16_t m_zero : 8;
|
||||
uint16_t m_type : 4;
|
||||
uint16_t m_storage : 1;
|
||||
uint16_t m_dpl : 2;
|
||||
uint16_t m_present : 1;
|
||||
uint16_t m_offset2;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
29
src/x86/interrupts.c
Normal file
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,23 +0,0 @@
|
||||
#include "../interrupts.hpp"
|
||||
#include "idt.hpp"
|
||||
#include "inthandlers.hpp"
|
||||
|
||||
kernel::Interrupts::Interrupts()
|
||||
{
|
||||
idt[0] = InterruptDescriptor((void*) &divisionByZero, InterruptDescriptor::INT32, 0);
|
||||
idt[8] = InterruptDescriptor((void*) &doubleFaultHandler, InterruptDescriptor::INT32, 0);
|
||||
idt[0x80] = InterruptDescriptor((void*) &syscallHandler, InterruptDescriptor::INT32, 0);
|
||||
// Load interrupt handlers
|
||||
// Configure PIC
|
||||
_lidt();
|
||||
}
|
||||
|
||||
inline void kernel::Interrupts::enable()
|
||||
{
|
||||
asm("sti");
|
||||
}
|
||||
|
||||
inline void kernel::Interrupts::disable()
|
||||
{
|
||||
asm("cli");
|
||||
}
|
||||
54
src/x86/interrupts.h
Normal file
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);
|
||||
@@ -1,39 +0,0 @@
|
||||
#include "inthandlers.hpp"
|
||||
|
||||
char* display = (char*) 0xC00B8000;
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void divisionByZero(void* frame)
|
||||
{
|
||||
*display = 'z';
|
||||
display += 2;
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void gpFaultHandler(void* frame, unsigned int error)
|
||||
{
|
||||
*display = 'a';
|
||||
display += 2;
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void pageFaultHandler(void* frame, unsigned int error)
|
||||
{
|
||||
*display = '0';
|
||||
display += 2;
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void doubleFaultHandler(void* frame, unsigned int error)
|
||||
{
|
||||
*display = '#';
|
||||
asm("hlt");
|
||||
}
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void syscallHandler(void* frame)
|
||||
{
|
||||
*display = 'z';
|
||||
display += 2;
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef INTHANDLERS_H
|
||||
#define INTHANDLERS_H
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void divisionByZero(void* frame);
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void gpFaultHandler(void* frame, unsigned int error);
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void pageFaultHandler(void* frame, unsigned int error);
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void doubleFaultHandler(void* frame, unsigned int error);
|
||||
|
||||
__attribute__ ((interrupt))
|
||||
void syscallHandler(void* frame);
|
||||
|
||||
#endif
|
||||
41
src/x86/isr.c
Normal file
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);
|
||||
@@ -33,4 +33,10 @@ SECTIONS
|
||||
LOAD_END = ADDR(.data) + SIZEOF(.data) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
||||
BSS_END = ADDR(.bss) + SIZEOF(.bss) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
||||
IMAGE_SIZE = ((BSS_END - LOAD_START) + (4096 - ((BSS_END - LOAD_START) % 4096))) / 4096;
|
||||
|
||||
_pageMapLocation = 0xFF800000;
|
||||
_heapLocation = 0xFFB00000;
|
||||
_heapSize = 0x100000;
|
||||
_kernelStart = VIRTUAL_BASE;
|
||||
_kernel_end = VIRTUAL_BASE + (4096 * IMAGE_SIZE);
|
||||
}
|
||||
|
||||
100
src/x86/mmap.cpp
100
src/x86/mmap.cpp
@@ -1,100 +0,0 @@
|
||||
#include "../mmap.hpp"
|
||||
#include "pagetableentry.hpp"
|
||||
|
||||
int kernel::mmap(MemoryAllocator& allocator, void* start, size_t length, int flags)
|
||||
{
|
||||
if((size_t) start % 4096 != 0)
|
||||
return -1;
|
||||
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
|
||||
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
|
||||
size_t tableIndex = (size_t) start / 4096;
|
||||
for(int i = (int) length; i > 0; i -= 4096)
|
||||
{
|
||||
size_t directoryIndex = tableIndex / 1024;
|
||||
if(!pageDirectory[directoryIndex].getPresent())
|
||||
{
|
||||
physaddr_t newPT = allocator.allocate(4096);
|
||||
if(newPT == 0)
|
||||
return -1;
|
||||
pageDirectory[directoryIndex] = newPT;
|
||||
pageDirectory[directoryIndex].setPresent(true);
|
||||
pageDirectory[directoryIndex].setUsermode(false);
|
||||
pageDirectory[directoryIndex].setRw(true);
|
||||
}
|
||||
if(!pageTables[tableIndex].getPresent())
|
||||
{
|
||||
physaddr_t page = allocator.allocate(4096);
|
||||
pageTables[tableIndex] = page;
|
||||
pageTables[tableIndex].setPresent(true);
|
||||
pageTables[tableIndex].setUsermode(false);
|
||||
if(flags & MMAP_RW)
|
||||
pageTables[tableIndex].setRw(true);
|
||||
|
||||
}
|
||||
tableIndex++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kernel::munmap(MemoryAllocator& allocator, void* start, size_t length)
|
||||
{
|
||||
if((size_t) start % 4096 != 0)
|
||||
return -1;
|
||||
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
|
||||
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
|
||||
size_t tableIndex = (size_t) start / 4096;
|
||||
for(int i = (int) length; i > 0; i -= 4096)
|
||||
{
|
||||
size_t directoryIndex = tableIndex / 1024;
|
||||
if(pageDirectory[directoryIndex].getPresent())
|
||||
{
|
||||
pageTables[tableIndex] = 0;
|
||||
pageTables[tableIndex].setPresent(false);
|
||||
pageTables[tableIndex].setUsermode(false);
|
||||
pageTables[tableIndex].setRw(false);
|
||||
}
|
||||
tableIndex++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool kernel::isMapped(void* addr)
|
||||
{
|
||||
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
|
||||
size_t tableIndex = (size_t) addr / 4096;
|
||||
size_t directoryIndex = tableIndex / 1024;
|
||||
if(pageDirectory[directoryIndex].getPresent())
|
||||
{
|
||||
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
|
||||
return pageTables[tableIndex].getPresent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
physaddr_t kernel::getPhysicalAddress(void* addr)
|
||||
{
|
||||
PageTableEntry* pageTables = (PageTableEntry*) 0xFFC00000;
|
||||
size_t tableIndex = (size_t) addr / 4096;
|
||||
return pageTables[tableIndex].getPhysicalAddress() + ((size_t) addr & 0xFFF);
|
||||
}
|
||||
|
||||
int kernel::createAddressSpace(void* table)
|
||||
{
|
||||
if(((size_t) table & 0xFFF) != 0)
|
||||
return -1;
|
||||
PageTableEntry* pageDirectory = (PageTableEntry*) 0xFFFFF000;
|
||||
PageTableEntry* newDirectory = (PageTableEntry*) table;
|
||||
newDirectory[1022] = pageDirectory[1022];
|
||||
newDirectory[1023] = pageDirectory[1023];
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kernel::loadAddressSpace(physaddr_t table)
|
||||
{
|
||||
if((table & 0xFFF) != 0)
|
||||
return -1;
|
||||
asm("mov %0, %%cr3"
|
||||
:
|
||||
: "r" (table));
|
||||
return 0;
|
||||
}
|
||||
123
src/x86/mmgr.c
Normal file
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;
|
||||
}
|
||||
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,94 +0,0 @@
|
||||
/*
|
||||
* Define constants for the multiboot header. See Multuboot 2 Specifications for details.
|
||||
*/
|
||||
.set align, 1<<0
|
||||
.set meminfo, 1<<1
|
||||
.set magic, 0xE85250D6
|
||||
.set arch, 0
|
||||
.set headerLength, _multibootHeaderEnd - _multibootHeaderStart
|
||||
.set checksum, -(magic + arch + headerLength)
|
||||
|
||||
.set tagNotOptional, 0
|
||||
|
||||
.set tagInfoRequestType, 1
|
||||
.set tagInfoRequestSize, _multibootInfoTagEnd - _multibootInfoTagStart
|
||||
.set requestBootCommand, 1
|
||||
.set requestBootLoaderName, 2
|
||||
.set requestBootModules, 3
|
||||
.set requestMemoryInfo, 4
|
||||
.set requestBootDevice, 5
|
||||
.set requestMemoryMap, 6
|
||||
|
||||
.set tagAddressType, 2
|
||||
.set tagAddressSize, 24
|
||||
.set tagAddressHeaderLocation, LOAD_START
|
||||
.set tagAddressLoadStart, LOAD_START
|
||||
.set tagAddressLoadEnd, LOAD_END
|
||||
.set tagAddressBSSEnd, BSS_END
|
||||
|
||||
.set tagEntryType, 3
|
||||
.set tagEntrySize, 12
|
||||
.set tagEntryAddress, _start - (0xFF900000 - 0x100000)
|
||||
|
||||
.set tagModuleAlignType, 6
|
||||
.set tagModuleAlignSize, 8
|
||||
|
||||
/*
|
||||
* Each multiboot tag must be 8-byte aligned, or GRUB will not be able to read the header.
|
||||
*/
|
||||
.align 8
|
||||
_multibootHeaderStart:
|
||||
|
||||
.long magic
|
||||
.long arch
|
||||
.long headerLength
|
||||
.long checksum
|
||||
|
||||
.align 8
|
||||
|
||||
_multibootInfoTagStart:
|
||||
.short tagInfoRequestType
|
||||
.short tagNotOptional
|
||||
.long tagInfoRequestSize
|
||||
.long requestBootCommand
|
||||
.long requestBootLoaderName
|
||||
.long requestBootModules
|
||||
.long requestMemoryInfo
|
||||
.long requestBootDevice
|
||||
.long requestMemoryMap
|
||||
_multibootInfoTagEnd:
|
||||
|
||||
.align 8
|
||||
|
||||
.short tagAddressType
|
||||
.short tagNotOptional
|
||||
.long tagAddressSize
|
||||
.long tagAddressHeaderLocation
|
||||
.long tagAddressLoadStart
|
||||
.long tagAddressLoadEnd
|
||||
.long tagAddressBSSEnd
|
||||
|
||||
.align 8
|
||||
|
||||
.short tagEntryType
|
||||
.short tagNotOptional
|
||||
.long tagEntrySize
|
||||
.long tagEntryAddress
|
||||
|
||||
.align 8
|
||||
|
||||
.short tagModuleAlignType
|
||||
.short tagNotOptional
|
||||
.long tagModuleAlignSize
|
||||
|
||||
.align 8
|
||||
|
||||
/*
|
||||
* Terminate list of multiboot header tags.
|
||||
* Ending tag has type = 0, flags = 0, size = 8
|
||||
*/
|
||||
.long 0
|
||||
.long 8
|
||||
|
||||
_multibootHeaderEnd:
|
||||
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
* PageTableEntry.cpp
|
||||
*
|
||||
* Created on: May 22, 2019
|
||||
* Author: nathan
|
||||
*/
|
||||
|
||||
#include "pagetableentry.hpp"
|
||||
|
||||
namespace kernel {
|
||||
|
||||
static_assert(sizeof(PageTableEntry) == 4, "PTE structure is the wrong size!");
|
||||
|
||||
PageTableEntry::PageTableEntry() {
|
||||
this->present = 0;
|
||||
this->rw = 0;
|
||||
this->usermode = 0;
|
||||
this->writeThrough = 0;
|
||||
this->cacheDisable = 0;
|
||||
this->accessed = 0;
|
||||
this->dirty = 0;
|
||||
this->pat = 0;
|
||||
this->global = 0;
|
||||
this->shared = 0;
|
||||
this->ignored = 0;
|
||||
this->physicalAddress = 0;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getAccessed() const {
|
||||
return accessed == 1;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getCacheDisable() const
|
||||
{
|
||||
return cacheDisable == 1;
|
||||
}
|
||||
|
||||
void PageTableEntry::setCacheDisable(bool cacheDisable)
|
||||
{
|
||||
this->cacheDisable = cacheDisable ? 1 : 0;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getDirty() const
|
||||
{
|
||||
return dirty == 1;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getGlobal() const
|
||||
{
|
||||
return global == 1;
|
||||
}
|
||||
|
||||
void PageTableEntry::setGlobal(bool global)
|
||||
{
|
||||
this->global = global ? 1 : 0;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getPat() const
|
||||
{
|
||||
return pat == 1;
|
||||
}
|
||||
|
||||
void PageTableEntry::setPat(bool pat)
|
||||
{
|
||||
this->pat = pat ? 1 : 0;
|
||||
}
|
||||
|
||||
physaddr_t PageTableEntry::getPhysicalAddress() const {
|
||||
physaddr_t physicalAddress = this->physicalAddress;
|
||||
return physicalAddress << 12;
|
||||
}
|
||||
|
||||
physaddr_t PageTableEntry::setPhysicalAddress(physaddr_t physicalAddress)
|
||||
{
|
||||
this->physicalAddress = physicalAddress >> 12;
|
||||
return this->physicalAddress << 12;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getPresent() const
|
||||
{
|
||||
return present == 1;
|
||||
}
|
||||
|
||||
void PageTableEntry::setPresent(bool present)
|
||||
{
|
||||
this->present = present ? 1 : 0;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getRw() const
|
||||
{
|
||||
return rw == 1;
|
||||
}
|
||||
|
||||
void PageTableEntry::setRw(bool rw)
|
||||
{
|
||||
this->rw = rw ? 1 : 0;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getUsermode() const
|
||||
{
|
||||
return usermode == 1;
|
||||
}
|
||||
|
||||
void PageTableEntry::setUsermode(bool usermode)
|
||||
{
|
||||
this->usermode = usermode ? 1 : 0;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getWriteThrough() const {
|
||||
return writeThrough == 1;
|
||||
}
|
||||
|
||||
bool PageTableEntry::getShared() const
|
||||
{
|
||||
return shared == 1;
|
||||
}
|
||||
|
||||
void PageTableEntry::setShared(bool shared)
|
||||
{
|
||||
this->shared = shared ? 1 : 0;
|
||||
}
|
||||
|
||||
void PageTableEntry::setWriteThrough(bool writeThrough)
|
||||
{
|
||||
this->writeThrough = writeThrough ? 1 : 0;
|
||||
}
|
||||
|
||||
physaddr_t PageTableEntry::operator=(physaddr_t rhs)
|
||||
{
|
||||
return setPhysicalAddress(rhs);
|
||||
}
|
||||
|
||||
PageTableEntry PageTableEntry::operator=(PageTableEntry rhs)
|
||||
{
|
||||
uint32_t* iThis = (uint32_t*) this;
|
||||
uint32_t* iThat = (uint32_t*) &rhs;
|
||||
*iThis = *iThat;
|
||||
return rhs;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
#ifndef SRC_PAGETABLEENTRY_H_
|
||||
#define SRC_PAGETABLEENTRY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../systypes.hpp"
|
||||
|
||||
namespace kernel {
|
||||
|
||||
class PageTableEntry {
|
||||
public:
|
||||
PageTableEntry();
|
||||
bool getAccessed() const;
|
||||
bool getCacheDisable() const;
|
||||
void setCacheDisable(bool cacheDisable);
|
||||
bool getDirty() const;
|
||||
bool getGlobal() const;
|
||||
void setGlobal(bool global);
|
||||
bool getPat() const;
|
||||
void setPat(bool pat);
|
||||
physaddr_t getPhysicalAddress() const;
|
||||
physaddr_t setPhysicalAddress(physaddr_t physicalAddress);
|
||||
bool getPresent() const;
|
||||
void setPresent(bool present);
|
||||
bool getRw() const;
|
||||
void setRw(bool rw);
|
||||
bool getShared() const;
|
||||
void setShared(bool shared);
|
||||
bool getUsermode() const;
|
||||
void setUsermode(bool usermode);
|
||||
bool getWriteThrough() const;
|
||||
void setWriteThrough(bool writeThrough);
|
||||
physaddr_t operator=(physaddr_t rhs);
|
||||
PageTableEntry operator=(PageTableEntry rhs);
|
||||
|
||||
private:
|
||||
uint32_t present : 1;
|
||||
uint32_t rw : 1;
|
||||
uint32_t usermode : 1;
|
||||
uint32_t writeThrough : 1;
|
||||
uint32_t cacheDisable : 1;
|
||||
uint32_t accessed : 1;
|
||||
uint32_t dirty : 1;
|
||||
uint32_t pat : 1;
|
||||
uint32_t global : 1;
|
||||
uint32_t shared : 1;
|
||||
uint32_t ignored : 2;
|
||||
uint32_t physicalAddress : 20;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,13 +0,0 @@
|
||||
.global outb
|
||||
outb:
|
||||
mov 4(%esp), %dx
|
||||
mov 8(%esp), %al
|
||||
out %al, %dx
|
||||
ret
|
||||
|
||||
.global inb
|
||||
inb:
|
||||
mov 4(%esp), %dx
|
||||
xor %eax, %eax
|
||||
in %dx, %al
|
||||
ret
|
||||
@@ -1,8 +0,0 @@
|
||||
#ifndef PIO_H
|
||||
#define PIO_H
|
||||
|
||||
extern "C" void outb(short port, char data);
|
||||
|
||||
extern "C" char inb(short port);
|
||||
|
||||
#endif
|
||||
68
src/x86/putc.c
Normal file
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
|
||||
}
|
||||
Reference in New Issue
Block a user