5
.gitignore
vendored
5
.gitignore
vendored
@@ -5,6 +5,8 @@ quark-kernel
|
|||||||
|
|
||||||
autom4te.cache/
|
autom4te.cache/
|
||||||
.deps
|
.deps
|
||||||
|
.dirstamp
|
||||||
|
.vscode
|
||||||
aclocal.m4
|
aclocal.m4
|
||||||
ar-lib
|
ar-lib
|
||||||
compile
|
compile
|
||||||
@@ -23,4 +25,5 @@ stamp-h1
|
|||||||
*~
|
*~
|
||||||
|
|
||||||
rootfs/apps
|
rootfs/apps
|
||||||
test/
|
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_PREREQ([2.69])
|
||||||
AC_INIT([quark-kernel], [pre-alpha])
|
AC_INIT([quark-kernel], [pre-alpha])
|
||||||
AM_INIT_AUTOMAKE([-Wall foreign])
|
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
|
||||||
AC_CONFIG_SRCDIR([src/tty.cpp])
|
AC_CONFIG_SRCDIR([src/kernel.c])
|
||||||
AC_CONFIG_HEADERS([src/config.h])
|
AC_CONFIG_HEADERS([src/config.h])
|
||||||
|
|
||||||
# Checks for programs.
|
# Checks for programs.
|
||||||
AC_PROG_CXX
|
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AM_PROG_AS
|
AM_PROG_AS
|
||||||
AM_PROG_AR
|
AM_PROG_AR
|
||||||
AC_PROG_RANLIB
|
AC_PROG_RANLIB
|
||||||
|
|
||||||
# Checks for header files.
|
# Checks for header files.
|
||||||
AC_CHECK_HEADERS([stddef.h stdint.h])
|
AC_CHECK_HEADERS([stddef.h stdint.h stdarg.h])
|
||||||
|
|
||||||
# Checks for typedefs, structures, and compiler characteristics.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_CHECK_HEADER_STDBOOL
|
AC_CHECK_HEADER_STDBOOL
|
||||||
|
|||||||
117
include/elf.h
Normal file
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
|
#pragma once
|
||||||
#define SYSTYPES_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#if defined __i386__ || __arm__
|
#if defined __i386__ || __arm__
|
||||||
typedef uint32_t physaddr_t;
|
typedef uint32_t physaddr_t;
|
||||||
@@ -10,6 +8,4 @@ typedef uint32_t physaddr_t;
|
|||||||
typedef uint64_t physaddr_t;
|
typedef uint64_t physaddr_t;
|
||||||
#else
|
#else
|
||||||
typedef uint64_t physaddr_t;
|
typedef uint64_t physaddr_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
9
include/types/status.h
Normal file
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" {
|
menuentry "Quark OS" {
|
||||||
multiboot2 /apps/quark-kernel
|
multiboot2 /apps/quark-kernel
|
||||||
module2 /apps/test
|
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,20 @@
|
|||||||
noinst_PROGRAMS = quark-kernel
|
noinst_PROGRAMS = quark-kernel
|
||||||
quark_kernel_SOURCES = quarkkernel.cpp elf.cpp tty.cpp systeminfo.cpp util.cpp memorymap.cpp buddyallocator.cpp
|
quark_kernel_SOURCES = kernel.c memorymap.c pageallocator.c priorityqueue.c stdio.c string.c
|
||||||
quark_kernel_LDADD = -lgcc
|
quark_kernel_LDADD = -lgcc
|
||||||
quark_kernel_CPPFLAGS = -ffreestanding -mgeneral-regs-only -O0 -Wall -fno-exceptions -fno-rtti -ggdb
|
quark_kernel_CFLAGS = -I$(top_srcdir)/include -ffreestanding -mgeneral-regs-only -O0 -Wall -ggdb
|
||||||
quark_kernel_LDFLAGS = -nostdlib
|
quark_kernel_LDFLAGS = -nostdlib
|
||||||
|
|
||||||
if x86
|
if x86
|
||||||
quark_kernel_SOURCES += x86/pagetableentry.cpp \
|
quark_kernel_SOURCES += x86/mmgr.c \
|
||||||
x86/mmap.cpp \
|
x86/putc.c \
|
||||||
x86/interrupts.cpp \
|
x86/multiboot2.c \
|
||||||
x86/inthandlers.cpp \
|
x86/interrupts.c \
|
||||||
x86/interruptdescriptor.cpp \
|
x86/apic.c \
|
||||||
x86/idt.S \
|
x86/isr.c \
|
||||||
x86/entry.S \
|
x86/msr.c \
|
||||||
x86/pio.S \
|
x86/quark_x86.c \
|
||||||
x86/multiboot2header.S
|
x86/entry.S
|
||||||
quark_kernel_LDFLAGS += -T x86/linker.ld
|
quark_kernel_LDFLAGS += -T x86/linker.ld
|
||||||
quark_kernel_DEPENDENCIES = x86/linker.ld
|
quark_kernel_DEPENDENCIES = x86/linker.ld
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
102
src/allocator.cpp
Normal file
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);
|
||||||
301
src/x86/entry.S
301
src/x86/entry.S
@@ -1,5 +1,98 @@
|
|||||||
.section .multiboot
|
.section .multiboot
|
||||||
.include "x86/multiboot2header.S"
|
|
||||||
|
/*
|
||||||
|
* Define constants for the multiboot header. See Multiboot 2 Specifications for details.
|
||||||
|
*/
|
||||||
|
.set align, 1<<0
|
||||||
|
.set meminfo, 1<<1
|
||||||
|
.set magic, 0xE85250D6
|
||||||
|
.set arch, 0
|
||||||
|
.set headerLength, _multibootHeaderEnd - _multibootHeaderStart
|
||||||
|
.set checksum, -(magic + arch + headerLength)
|
||||||
|
|
||||||
|
.set tagNotOptional, 0
|
||||||
|
|
||||||
|
.set tagInfoRequestType, 1
|
||||||
|
.set tagInfoRequestSize, _multibootInfoTagEnd - _multibootInfoTagStart
|
||||||
|
.set requestBootCommand, 1
|
||||||
|
.set requestBootLoaderName, 2
|
||||||
|
.set requestBootModules, 3
|
||||||
|
.set requestMemoryInfo, 4
|
||||||
|
.set requestBootDevice, 5
|
||||||
|
.set requestMemoryMap, 6
|
||||||
|
|
||||||
|
.set tagAddressType, 2
|
||||||
|
.set tagAddressSize, 24
|
||||||
|
.set tagAddressHeaderLocation, LOAD_START
|
||||||
|
.set tagAddressLoadStart, LOAD_START
|
||||||
|
.set tagAddressLoadEnd, LOAD_END
|
||||||
|
.set tagAddressBSSEnd, BSS_END
|
||||||
|
|
||||||
|
.set tagEntryType, 3
|
||||||
|
.set tagEntrySize, 12
|
||||||
|
.set tagEntryAddress, _start - (0xFF900000 - 0x100000)
|
||||||
|
|
||||||
|
.set tagModuleAlignType, 6
|
||||||
|
.set tagModuleAlignSize, 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each multiboot tag must be 8-byte aligned, or GRUB will not be able to read the header.
|
||||||
|
*/
|
||||||
|
.align 8
|
||||||
|
_multibootHeaderStart:
|
||||||
|
|
||||||
|
.long magic
|
||||||
|
.long arch
|
||||||
|
.long headerLength
|
||||||
|
.long checksum
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
|
||||||
|
_multibootInfoTagStart:
|
||||||
|
.short tagInfoRequestType
|
||||||
|
.short tagNotOptional
|
||||||
|
.long tagInfoRequestSize
|
||||||
|
.long requestBootCommand
|
||||||
|
.long requestBootLoaderName
|
||||||
|
.long requestBootModules
|
||||||
|
.long requestMemoryInfo
|
||||||
|
.long requestBootDevice
|
||||||
|
.long requestMemoryMap
|
||||||
|
_multibootInfoTagEnd:
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
|
||||||
|
.short tagAddressType
|
||||||
|
.short tagNotOptional
|
||||||
|
.long tagAddressSize
|
||||||
|
.long tagAddressHeaderLocation
|
||||||
|
.long tagAddressLoadStart
|
||||||
|
.long tagAddressLoadEnd
|
||||||
|
.long tagAddressBSSEnd
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
|
||||||
|
.short tagEntryType
|
||||||
|
.short tagNotOptional
|
||||||
|
.long tagEntrySize
|
||||||
|
.long tagEntryAddress
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
|
||||||
|
.short tagModuleAlignType
|
||||||
|
.short tagNotOptional
|
||||||
|
.long tagModuleAlignSize
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Terminate list of multiboot header tags.
|
||||||
|
* Ending tag has type = 0, flags = 0, size = 8
|
||||||
|
*/
|
||||||
|
.long 0
|
||||||
|
.long 8
|
||||||
|
|
||||||
|
_multibootHeaderEnd:
|
||||||
|
|
||||||
.section .rodata
|
.section .rodata
|
||||||
|
|
||||||
@@ -31,7 +124,7 @@ _tempPgDir:
|
|||||||
_tempIdentityMap:
|
_tempIdentityMap:
|
||||||
.skip 4096
|
.skip 4096
|
||||||
_tempPgTable:
|
_tempPgTable:
|
||||||
.skip 8192
|
.skip 4096
|
||||||
|
|
||||||
_bootCmdLine:
|
_bootCmdLine:
|
||||||
.skip 64
|
.skip 64
|
||||||
@@ -50,181 +143,57 @@ memory_map:
|
|||||||
.global _start
|
.global _start
|
||||||
.type _start, @function
|
.type _start, @function
|
||||||
_start:
|
_start:
|
||||||
|
|
||||||
|
cli
|
||||||
|
|
||||||
|
# This platform reqires a Multiboot2 bootloader.
|
||||||
cmp $0x36d76289, %eax
|
cmp $0x36d76289, %eax
|
||||||
jne _err
|
jne .err
|
||||||
|
|
||||||
movb $64, 0xB8000
|
# Initialize stack in physical address space
|
||||||
|
mov $stackTop, %esp
|
||||||
|
sub $BASE_DIFF, %esp
|
||||||
|
|
||||||
mov $system_info, %edi
|
# Push physical address of identity map
|
||||||
sub $BASE_DIFF, %edi
|
|
||||||
add $8, %ebx
|
|
||||||
|
|
||||||
switch:
|
|
||||||
mov (%ebx), %eax
|
|
||||||
cmp $0, %eax
|
|
||||||
je s_end
|
|
||||||
cmp $1, %eax
|
|
||||||
je tag_1
|
|
||||||
cmp $3, %eax
|
|
||||||
je tag_3
|
|
||||||
cmp $4, %eax
|
|
||||||
je tag_4
|
|
||||||
cmp $6, %eax
|
|
||||||
je tag_6
|
|
||||||
cmp $21, %eax
|
|
||||||
je tag_21
|
|
||||||
jmp def
|
|
||||||
|
|
||||||
# Boot command line
|
|
||||||
tag_1:
|
|
||||||
mov 4(%ebx), %ecx
|
|
||||||
sub $8, %ecx
|
|
||||||
mov %ebx, %esi
|
|
||||||
add $8, %esi
|
|
||||||
mov $_bootCmdLine, %edi
|
|
||||||
sub $BASE_DIFF, %edi
|
|
||||||
rep movsb
|
|
||||||
mov $system_info, %edi
|
|
||||||
sub $BASE_DIFF, %edi
|
|
||||||
jmp def
|
|
||||||
|
|
||||||
tag_3:
|
|
||||||
mov 8(%ebx), %esi
|
|
||||||
mov (%esi), %eax
|
|
||||||
mov %al, (0xB8004)
|
|
||||||
mov %ah, (0xB8006)
|
|
||||||
shr $16, %eax
|
|
||||||
mov %al, (0xB8008)
|
|
||||||
mov %ah, (0xB800a)
|
|
||||||
jmp def
|
|
||||||
|
|
||||||
# Basic memory info
|
|
||||||
tag_4:
|
|
||||||
mov 8(%ebx), %eax
|
|
||||||
mov %eax, (%edi)
|
|
||||||
mov 12(%ebx), %eax
|
|
||||||
mov %eax, 4(%edi)
|
|
||||||
jmp def
|
|
||||||
|
|
||||||
# Memory map
|
|
||||||
tag_6:
|
|
||||||
mov $memory_map, %esi
|
|
||||||
sub $BASE_DIFF, %esi # set esi to point to the table in the kernel image
|
|
||||||
mov 4(%ebx), %ecx
|
|
||||||
sub $16, %ecx # set ecx to store the size of the table provided by the bootloader
|
|
||||||
mov 8(%ebx), %edx # set edx to store the size of each table entry
|
|
||||||
add $16, %ebx # move ebx up to the first entry
|
|
||||||
1: mov (%ebx), %eax
|
|
||||||
mov %eax, (%esi) # save the address of that region in memory
|
|
||||||
mov 8(%ebx), %eax
|
|
||||||
mov %eax, 4(%esi) # save the size of that region in memory
|
|
||||||
mov 16(%ebx), %eax
|
|
||||||
mov %eax, 8(%esi) # save the type of memory in that region
|
|
||||||
add $12, %esi # move esi to the next entry in the kernel's array
|
|
||||||
add %edx, %ebx # move ebx to the next entry in the bootloader's array
|
|
||||||
sub %edx, %ecx # subtract the size of an entry from ecx.
|
|
||||||
jnz 1b # loop if there are entries left
|
|
||||||
mov $0, %eax
|
|
||||||
mov %eax, (%esi)
|
|
||||||
mov %eax, 4(%esi)
|
|
||||||
mov %eax, 8(%esi)
|
|
||||||
jmp switch
|
|
||||||
|
|
||||||
# Program image location
|
|
||||||
tag_21:
|
|
||||||
mov 8(%ebx), %eax
|
|
||||||
mov %eax, 8(%edi)
|
|
||||||
jmp def
|
|
||||||
|
|
||||||
def:
|
|
||||||
mov 4(%ebx), %eax
|
|
||||||
add $7, %eax
|
|
||||||
and $0xFFFFFFF8, %eax
|
|
||||||
add %eax, %ebx
|
|
||||||
jmp switch
|
|
||||||
s_end:
|
|
||||||
|
|
||||||
movb $64, 0xB8002
|
|
||||||
|
|
||||||
mov $0, %ecx
|
|
||||||
1:
|
|
||||||
# Generate a page table entry pointing to a page in the kernel binary
|
|
||||||
mov %ecx, %eax
|
|
||||||
mov $4096, %edx
|
|
||||||
mul %edx
|
|
||||||
or $3, %eax
|
|
||||||
|
|
||||||
# Load the address of the temporary page table and translate it to a physical address
|
|
||||||
mov $_tempPgTable, %edi
|
|
||||||
sub $BASE_DIFF, %edi
|
|
||||||
|
|
||||||
# Save the PTE into an entry in the temporary page table
|
|
||||||
mov %eax, (%edi, %ecx, 4)
|
|
||||||
|
|
||||||
# Load the address of the identity map and translate it to a physical address
|
|
||||||
mov $_tempIdentityMap, %edi
|
|
||||||
sub $BASE_DIFF, %edi
|
|
||||||
|
|
||||||
# Save the PTE into an entry in the identity map
|
|
||||||
mov %eax, (%edi, %ecx, 4)
|
|
||||||
|
|
||||||
# Increment count and loop
|
|
||||||
inc %ecx
|
|
||||||
mov $IMAGE_SIZE, %edx
|
|
||||||
add $256, %edx
|
|
||||||
cmp %edx, %ecx
|
|
||||||
jne 1b
|
|
||||||
|
|
||||||
# Load the physical address of the identity map, and generate a PDE
|
|
||||||
mov $_tempIdentityMap, %eax
|
mov $_tempIdentityMap, %eax
|
||||||
sub $BASE_DIFF, %eax
|
sub $BASE_DIFF, %eax
|
||||||
or $3, %eax
|
push %eax
|
||||||
|
|
||||||
# Load the physical address of the page directory
|
# Push physical address of page table
|
||||||
mov $_tempPgDir, %edi
|
|
||||||
sub $BASE_DIFF, %edi
|
|
||||||
|
|
||||||
# Save the PDE to the first element in the page directory
|
|
||||||
mov %eax, (%edi)
|
|
||||||
|
|
||||||
# Load the physical address of the temporary page table, and generate a PDE
|
|
||||||
mov $_tempPgTable, %eax
|
mov $_tempPgTable, %eax
|
||||||
sub $BASE_DIFF, %eax
|
sub $BASE_DIFF, %eax
|
||||||
or $3, %eax
|
push %eax
|
||||||
|
|
||||||
# Save the PDE to the entry corresponding to 0xC0000000
|
# Push physical address of page directory
|
||||||
mov %eax, 4088(%edi)
|
mov $_tempPgDir, %eax
|
||||||
|
sub $BASE_DIFF, %eax
|
||||||
# Set the last entry in the page directory to point to the page directory itself
|
push %eax
|
||||||
mov %edi, %eax
|
|
||||||
or $3, %eax
|
|
||||||
mov %eax, 4092(%edi)
|
|
||||||
|
|
||||||
# Load the physical address of the page directory into CR3
|
# Load physical address of startPaging()
|
||||||
mov $_tempPgDir, %edi
|
mov $startPaging, %eax
|
||||||
sub $BASE_DIFF, %edi
|
sub $BASE_DIFF, %eax
|
||||||
mov %edi, %cr3
|
|
||||||
|
# Initialize paging
|
||||||
# Enable paging
|
call *%eax
|
||||||
mov %cr0, %eax
|
|
||||||
or $0x80010000, %eax
|
|
||||||
mov %eax, %cr0
|
|
||||||
|
|
||||||
# Jump into mapped kernel binary
|
# Jump into mapped kernel binary
|
||||||
lea 2f, %eax
|
lea 1f, %eax
|
||||||
jmp *%eax
|
jmp *%eax
|
||||||
2:
|
1:
|
||||||
# Delete PDE corresponding to identity map. We shouldn't need it anymore.
|
# Delete PDE corresponding to identity map. We shouldn't need it anymore.
|
||||||
movl $0, (_tempIdentityMap)
|
movl $0, (_tempIdentityMap)
|
||||||
|
|
||||||
# Reload page tables
|
# Flush TLB
|
||||||
mov %cr3, %eax
|
mov %cr3, %eax
|
||||||
mov %eax, %cr3
|
mov %eax, %cr3
|
||||||
|
|
||||||
# Initialize stack
|
# Initialize stack in virtual memory
|
||||||
mov $stackTop, %esp
|
mov $stackTop, %esp
|
||||||
|
|
||||||
|
# Load GPT
|
||||||
lgdt gdt_info
|
lgdt gdt_info
|
||||||
|
|
||||||
|
# Load segment registers
|
||||||
jmp $8, $.ldcs
|
jmp $8, $.ldcs
|
||||||
.ldcs:
|
.ldcs:
|
||||||
mov $16, %ax
|
mov $16, %ax
|
||||||
@@ -234,15 +203,21 @@ s_end:
|
|||||||
mov %ax, %fs
|
mov %ax, %fs
|
||||||
mov %ax, %ss
|
mov %ax, %ss
|
||||||
|
|
||||||
mov $_bootCmdLine, %eax
|
# Change EBX to point to the virtual address of the multiboot info
|
||||||
push %eax
|
# If the new pointer is out-of-bounds, error
|
||||||
|
add $0xFF800000, %ebx
|
||||||
# Call main function
|
cmp $0xFF800000, %ebx
|
||||||
call main
|
jl .err
|
||||||
|
cmp $0xFFC00000, %ebx
|
||||||
|
jge .err
|
||||||
|
|
||||||
_err:
|
# Call initialize(void* multibootInfo)
|
||||||
|
push %ebx
|
||||||
|
call initialize
|
||||||
|
|
||||||
|
.err:
|
||||||
cli
|
cli
|
||||||
3: hlt
|
2: hlt
|
||||||
jmp 3b
|
jmp 2b
|
||||||
|
|
||||||
.size _start, . - _start
|
.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);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0xFF900000;
|
. = 0xFF900000;
|
||||||
@@ -33,4 +33,10 @@ SECTIONS
|
|||||||
LOAD_END = ADDR(.data) + SIZEOF(.data) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
LOAD_END = ADDR(.data) + SIZEOF(.data) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
||||||
BSS_END = ADDR(.bss) + SIZEOF(.bss) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
BSS_END = ADDR(.bss) + SIZEOF(.bss) - (VIRTUAL_BASE - PHYSICAL_BASE);
|
||||||
IMAGE_SIZE = ((BSS_END - LOAD_START) + (4096 - ((BSS_END - LOAD_START) % 4096))) / 4096;
|
IMAGE_SIZE = ((BSS_END - LOAD_START) + (4096 - ((BSS_END - LOAD_START) % 4096))) / 4096;
|
||||||
|
|
||||||
|
_pageMapLocation = 0xFF800000;
|
||||||
|
_heapLocation = 0xFFB00000;
|
||||||
|
_heapSize = 0x100000;
|
||||||
|
_kernelStart = VIRTUAL_BASE;
|
||||||
|
_kernel_end = VIRTUAL_BASE + (4096 * IMAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|||||||
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